Historia pytania
Od początku istnienia Javy pojawiła się potrzeba zapisywania obiektów między sesjami działania aplikacji — przesyłania przez sieć, zapisywania w bazie danych lub na dysku. W tym celu wymyślono interfejs Serializable, który umożliwił przekształcanie obiektów w strumień bajtów i z powrotem (serializacja i deserializacja).
Problem
Jeśli klasa nie implementuje interfejsu Serializable, próba serializacji jej instancji wyrzuci wyjątek. Co więcej, serializacja zapisuje nie tylko wartości pól, ale i ich stan, więc niewłaściwa implementacja może prowadzić do nieoczekiwanej podatności, błędów przy przywracaniu obiektu, a nawet utraty danych.
Rozwiązanie
Interfejs Serializable jest interfejsem znacznikowym, czyli nie zawiera metod. Dla poprawnej serializacji warto wyraźnie podać serialVersionUID, a także używać słowa kluczowego transient dla pól, które nie powinny być serializowane.
Przykład kodu:
import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; private String username; private transient String password; // nie będzie serializowane public User(String username, String password) { this.username = username; this.password = password; } }
Kluczowe cechy:
Czy obowiązkowe jest wyraźne deklarowanie pola serialVersionUID?
Nie, nie jest to obowiązkowe, ale jeśli nie zostanie zadeklarowane, zostanie automatycznie wygenerowane. Jednak w przypadku zmian w klasie przywracanie starej wersji serializowanej może prowadzić do InvalidClassException. Dlatego lepiej zawsze wyraźnie deklarować to pole.
Czy pola statyczne są serializowane?
Nie, serializowane są tylko pola niestatyczne (instancyjne). Pola statyczne należą do klasy, a nie do obiektu, dlatego ich wartości podczas serializacji i deserializacji nie są zapisywane ani przywracane.
Czy można serializować obiekt, którego pola nie implementują Serializable?
Nie, jeśli chociaż jedno niestatyczne pole nie jest serializowalne i nie jest zadeklarowane jako transient, próba serializacji spowoduje wyrzucenie wyjątku NotSerializableException.
W aplikacji do przechowywania użytkowników nie podano serialVersionUID, a podczas modyfikacji kodu zmieniono strukturę klasy User. Przy uruchamianiu aplikacji pojawił się InvalidClassException i wszystkie zserializowane dane zostały utracone.
Zalety:
Wady:
W podobnym projekcie zawsze wyraźnie podawano serialVersionUID i wszystkie pola, które nie miały być serializowane, robiono transient. Dzięki temu zserializowane obiekty były pomyślnie ładowane po zmianie nieznacznej struktury klasy.
Zalety:
Wady: