Własna serializacja: writeObject i readObject
Przeciążaj writeObject i readObject na potrzeby szyfrowania, kompresji lub niestandardowej obsługi pól.
Własna serializacja: writeObject i readObject to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Gdy domyślna serializacja nie wystarcza
Domyślna serializacja zapisuje wszystkie pola inne niż transient bez zmian. Czasami potrzebne są szyfrowanie, kompresja lub inna reprezentacja danych. W takich sytuacjach przydatne są mechanizmy writeObject / readObject.
Deklarowanie writeObject
Należy dodać metodę private void writeObject(ObjectOutputStream oos). Java wywoła ją zamiast mechanizmu domyślnego. Dzięki temu można dokładnie kontrolować, co zostanie zapisane.
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // write non-transient fields normally
oos.writeUTF(encrypt(this.secret)); // write encrypted secret
}Deklarowanie readObject
Należy dodać metodę private void readObject(ObjectInputStream ois). Java wywoła ją podczas deserializacji. Dane należy odczytywać dokładnie w tej samej kolejności, w której zostały zapisane.
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // restore non-transient fields
this.secret = decrypt(ois.readUTF()); // decrypt and restore
}Kolejność ma znaczenie
Wszystko, co zostanie zapisane w writeObject, musi zostać odczytane w tej samej kolejności w readObject. Niezgodna kolejność powoduje StreamCorruptedException.
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.writeInt(version);
oos.writeUTF(data);
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
this.version = ois.readInt(); // same order
this.data = ois.readUTF();
}Kompresowanie danych podczas serializacji
W metodzie writeObject należy opakować strumień za pomocą GZIPOutputStream, aby skompresować duże pola, a następnie użyć GZIPInputStream w metodzie readObject, aby je zdekompresować.
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (GZIPOutputStream gz = new GZIPOutputStream(bos)) {
gz.write(largePayload.getBytes());
}
oos.writeObject(bos.toByteArray());
}Mechanizm readResolve
readResolve() jest wywoływana po deserializacji. Zwraca zastępczy obiekt — jest przydatna w przypadku singletonów i wyliczeń, aby po deserializacji zapewnić istnienie tylko jednej instancji.
public class AppConfig implements Serializable {
private static final AppConfig INSTANCE = new AppConfig();
private AppConfig() {}
public static AppConfig getInstance() { return INSTANCE; }
private Object readResolve() { return INSTANCE; } // return singleton
}Mechanizm writeReplace
writeReplace() jest wywoływana przed serializacją. Zwraca inny obiekt, który zostanie zserializowany zamiast bieżącego — jest przydatna w przypadku wzorców proxy i obiektów zastępczych używanych podczas serializacji.
private Object writeReplace() {
return new UserProxy(this.id); // serialize a lightweight proxy
}Walidowanie pól w readObject
Można dodać logikę walidacji wewnątrz readObject, aby odrzucać nieprawidłowe lub zmodyfikowane dane w ramach strategii ochrony wielowarstwowej.
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (age < 0 || age > 150) {
throw new InvalidObjectException("Invalid age: " + age);
}
}Obsługa zmian wersji
Należy użyć pola wersji w writeObject, aby metoda readObject mogła prawidłowo obsługiwać zarówno stare, jak i nowe formaty podczas migracji.
private static final int SERIAL_VERSION = 2;
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeInt(SERIAL_VERSION);
if (SERIAL_VERSION >= 2) oos.writeUTF(email); // new field
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
int v = ois.readInt();
if (v >= 2) this.email = ois.readUTF();
}Wzorzec proxy serializacji
Solidne podejście polega na napisaniu prywatnej statycznej klasy wewnętrznej, która przechwytuje minimalny stan, a następnie użyciu writeReplace do zapisania proxy i jego readResolve do odtworzenia oryginalnego obiektu.
Aspekty wydajnościowe
Niestandardowa serializacja zwiększa narzut związany z wywołaniami metod, ale może znacząco zmniejszyć rozmiar danych. Przed optymalizacją należy wykonać testy porównawcze; w celu uzyskania maksymalnej kontroli można użyć Externalizable.
Szybkie sprawdzenie
Jaki warunek musi być spełniony dla kolejności operacji w writeObject i readObject?
Podsumowanie
Należy nadpisywać writeObject / readObject, aby stosować szyfrowanie, kompresję lub niestandardowe formaty. W przypadku singletonów należy używać readResolve. Dane trzeba zawsze odczytywać w tej samej kolejności, w której zostały zapisane.
Często zadawane pytania
Czy lekcja „Własna serializacja: writeObject i readObject” jest bezpłatna?
Tak — pełny tekst „Własna serializacja: writeObject i readObject” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Własna serializacja: writeObject i readObject”?
Przeciążaj writeObject i readObject na potrzeby szyfrowania, kompresji lub niestandardowej obsługi pól. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Własna serializacja: writeObject i readObject”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Podstawy serializacji w Javie
- Pola transient i serialVersionUID
- Własna serializacja: writeObject i readObject
- Nowoczesne alternatywy: JSON i Protocol Buffers