Historia pytania:
Java od samego początku wspiera mechanizm serializacji obiektów przez interfejs Serializable. Czasami konieczne jest zachowanie stanu obiektu, ale nie wszystkie pola powinny być serializowane — na przykład mogą być wrażliwe z punktu widzenia bezpieczeństwa lub obliczane dynamicznie. Dla takich przypadków został wymyślony modyfikator transient.
Problem:
Jeśli serializujemy obiekt w całości, nie biorąc pod uwagę cech poszczególnych pól, można doprowadzić do wycieku prywatnych lub niestabilnych danych do serializacji. Dodatkowo, serializacja i deserializacja dużych lub tymczasowych pól (na przykład, strumieni, połączeń z bazą danych) może prowadzić do błędów lub obniżenia wydajności.
Rozwiązanie:
Użyj modyfikatora transient dla pól, które nie powinny być serializowane przy zachowywaniu obiektu. Takie pola są po prostu ignorowane przez mechanizm serializacji, a przy deserializacji otrzymują wartości domyślne (na przykład null dla typów referencyjnych lub 0 dla liczb).
Przykład kodu:
import java.io.*; class User implements Serializable { private String username; private transient String password; // Nie jest serializowane! public User(String username, String password) { this.username = username; this.password = password; } }
Kluczowe cechy:
Czy pole statyczne może być transient?
Odpowiedź: Można zadeklarować pole jako static transient, ale nie ma to sensu: pól statycznych i tak nie serializuje się, ponieważ należą do klasy, a nie do obiektu.
Czy można mieć pełną kontrolę nad serializacją pól transient?
Odpowiedź: Tak, implementując metody private void writeObject(ObjectOutputStream out) i private void readObject(ObjectInputStream in), można samodzielnie serializować nawet transient pola w razie potrzeby.
Przykład kodu:
private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); // out.writeObject(password); // jeśli trzeba jawnie serializować pole transient }
Co stanie się z final transient polem po deserializacji?
Odpowiedź: final transient pola również otrzymują wartości domyślne (zwykle zero lub null), ale potem nie można ich zmienić bez specjalnych sztuczek, co często prowadzi do błędów.
Zserializowano obiekt z polem transient DatabaseConnection. Po deserializacji próbowano wywołać metody tego połączenia — otrzymano NullPointerException.
Zalety:
Wady:
Zserializowano obiekt User z transient hasłem, przy deserializacji w readObject poproszono użytkownika o hasło lub przywrócono połączenie.
Zalety:
Wady: