Ce face transient
Serializarea Java transformă un obiect într-un șir de octeți (pentru un fișier sau rețea), iar deserializarea îl reconstruiește. Funcționează pentru clasele care implementează Serializable și salvează implicit toate câmpurile.
Un câmp transient este sărit: nu ajunge în octeți, iar după deserializare are valoarea implicită (null, 0, false). Se folosește pentru date secrete (parole), date care se pot recalcula (cache-uri) sau obiecte care nu pot fi serializate (conexiuni, fire de execuție).
Cuvântul este rar în codul modern: serializarea Java nativă este considerată riscantă și a fost înlocuită în majoritatea aplicațiilor de JSON sau alte formate. Unele biblioteci JSON respectă însă și ele transient.
Exemple
Exemplul 1: Câmpul transient nu supraviețuiește serializării
Obiectul este scris într-un array de octeți și citit înapoi. Emailul se păstrează; parola și cache-ul (transient) revin la null și 0. Clasa declară serialVersionUID, cerut de -Xlint.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Utilizator implements Serializable {
private static final long serialVersionUID = 1L;
final String email;
transient String parola;
transient int vizualizariCache;
Utilizator(String email, String parola) {
this.email = email;
this.parola = parola;
this.vizualizariCache = 42;
}
@Override
public String toString() {
return email + ", parola=" + parola + ", cache=" + vizualizariCache;
}
}
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Utilizator u = new Utilizator("ana@exemplu.ro", "secret123");
System.out.println("înainte: " + u);
ByteArrayOutputStream octeti = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(octeti)) {
out.writeObject(u);
}
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(octeti.toByteArray()))) {
Utilizator citit = (Utilizator) in.readObject();
System.out.println("după: " + citit);
}
}
}
Rezultat
înainte: ana@exemplu.ro, parola=secret123, cache=42
după: ana@exemplu.ro, parola=null, cache=0
Greșeli frecvente
- Crezi că
transientascunde câmpul și întoString(), loguri sau JSON-ul produs de orice bibliotecă. Afectează doar serializarea (și bibliotecile care aleg să îl respecte). - Te aștepți ca un câmp
transientsă primească la deserializare valoarea de la declarare (transient int x = 5;). Constructorul nu rulează, deci câmpul este 0. - Uiți
serialVersionUIDîntr-o clasăSerializable: cu-Xlint:all -Werrorcompilarea eșuează ([serial]).
Comenzi înrudite
volatile: volatile pe un câmp garantează că fiecare fir vede imediat ultima valoare scrisă; nu face însă operațiile compuse (x++) atomice.native: native declară o metodă fără corp, implementată în cod nativ (C, C++) și apelată prin JNI; nu se scrie aproape niciodată în aplicații obișnuite.Interfețe (interface, implements): O interfață (interface) descrie ce metode trebuie să aibă o clasă; clasa o promite cu implements și poate implementa mai multe interfețe.Modificatori de acces (public, protected, private): public, protected, private și lipsa modificatorului stabilesc cine poate vedea o clasă, un câmp, o metodă sau un constructor.