0Pricing
Java Academy · Lekcja

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

  1. Podstawy serializacji w Javie
  2. Pola transient i serialVersionUID
  3. Własna serializacja: writeObject i readObject
  4. Nowoczesne alternatywy: JSON i Protocol Buffers
← Powrót do Java Academy