Ay, aunque lo que más domino es Java, hay muchos conocimientos básicos de Java que no sé. Por ejemplo, la palabra clave transient nunca la había usado antes, así que no sabía para qué servía. Hoy, al hacer un examen escrito, encontré una pregunta sobre esto, así que dediqué un tiempo a organizar el uso de la palabra clave transient para ampliar mis conocimientos~~~ Bueno, basta de tonterías, comencemos:

1. Función y método de uso de transient

Todos sabemos que mientras un objeto implemente la interfaz Serializable, este objeto puede serializarse. Este modo de serialización de Java proporciona mucha comodidad a los desarrolladores; no necesitamos preocuparnos por el proceso de serialización específico. Siempre que la clase implemente la interfaz Serializable, todos los atributos y métodos de esta clase se serializarán automáticamente.

Sin embargo, en el proceso de desarrollo real, a menudo nos encontramos con este problema: algunos atributos de esta clase necesitan serializarse, mientras que otros no. Por ejemplo, si un usuario tiene información sensible (como contraseñas, números de tarjeta bancaria, etc.), por razones de seguridad, no se desea que se transmitan en operaciones de red (principalmente relacionadas con operaciones de serialización; también aplica a la caché de serialización local). A las variables correspondientes a esta información se les puede agregar la palabra clave transient. En otras palabras, el ciclo de vida de este campo solo existe en la memoria del llamante y no se escribirá en el disco para persistir.

En resumen, la palabra clave transient de Java nos ofrece comodidad. Solo necesitas implementar la interfaz Serializable y agregar la palabra clave transient antes de los atributos que no necesitan serialización. Al serializar el objeto, este atributo no se serializará al destino especificado.

Ejemplo

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @description Usar la palabra clave transient para no serializar una variable * Nota: al leer, el orden de los datos leídos debe ser coherente con el orden en que se guardaron * * @author Alexia * @date 2013-10-15 */ public class TransientTest { public static void main(String[] args) { User user = new User(); user.setUsername("Alexia"); user.setPasswd("123456"); System.out.println("read before Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("C:/user.txt")); os.writeObject(user); //Escribir el objeto User en un archivo os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { ObjectInputStream is = new ObjectInputStream(new FileInputStream( "C:/user.txt")); user = (User) is.readObject(); //Leer los datos de User desde el flujo is.close(); System.out.println("\nread after Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class User implements Serializable { private static final long serialVersionUID = 8294180014912103005L; private String username; private transient String passwd; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } }

La salida es:

read before Serializable: 
username: Alexia
password: 123456

read after Serializable: 
username: Alexia
password: null

El campo de contraseña es null, lo que indica que al deserializar no se obtuvo información del archivo.

2. Resumen del uso de transient

1) Una vez que una variable está modificada por transient, la variable ya no será parte de la persistencia del objeto; el contenido de esa variable no podrá ser accedido después de la serialización.

2) La palabra clave transient solo puede modificar variables, no métodos ni clases. Ten en cuenta que las variables locales no pueden ser modificadas por transient. Si la variable es una variable de clase definida por el usuario, entonces esa clase necesita implementar la interfaz Serializable.

3) Las variables modificadas por la palabra clave transient ya no pueden serializarse. Una variable estática, independientemente de si está modificada por transient, no puede serializarse.

El tercer punto puede confundir a algunos, porque descubren que después de agregar la palabra clave static al campo username en la clase User, el resultado del programa sigue siendo el mismo, es decir, el username de tipo static también se lee como "Alexia". ¿No contradice esto el tercer punto? En realidad, es así: el tercer punto es correcto (una variable estática, independientemente de si está modificada por transient, no puede serializarse). Después de la deserialización, el valor de la variable estática username en la clase es el valor de la variable estática correspondiente en el JVM actual. Este valor es del JVM, no se obtiene por deserialización. ¿No lo crees? Bien, a continuación lo demostraré:

Ejemplo

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @description Usar la palabra clave transient para no serializar una variable * Nota: al leer, el orden de los datos leídos debe ser coherente con el orden en que se guardaron * * @author Alexia * @date 2013-10-15 */ public class TransientTest { public static void main(String[] args) { User user = new User(); user.setUsername("Alexia"); user.setPasswd("123456"); System.out.println("read before Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("C:/user.txt")); os.writeObject(user); //Escribir el objeto User en un archivo os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { //Cambiar el valor de username antes de la deserialización User.username = "jmwang"; ObjectInputStream is = new ObjectInputStream(new FileInputStream( "C:/user.txt")); user = (User) is.readObject(); //Leer los datos de User desde el flujo is.close(); System.out.println("\nread after Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class User implements Serializable { private static final long serialVersionUID = 8294180014912103005L; public static String username; private transient String passwd; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } }

El resultado de la ejecución es:

read before Serializable: 
username: Alexia
password: 123456

read after Serializable: 
username: jmwang
password: null

Esto muestra que, después de la deserialización, el valor de la variable estática username en la clase es el valor de la variable estática correspondiente en el JVM actual, es decir, el valor modificado jmwang, no el valor Alexia del momento de la serialización.

3. Detalles del uso de transient: ¿las variables modificadas por la palabra clave transient realmente no pueden serializarse?

Considera el siguiente ejemplo:

Ejemplo

import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; /** * @descripiton Uso de la interfaz Externalizable * * @author Alexia * @date 2013-10-15 * */ public class ExternalizableTest implements Externalizable { private transient String content = "Sí, seré serializado, sin importar si estoy modificado por la palabra clave transient"; @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(content); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { content = (String) in.readObject(); } public static void main(String[] args) throws Exception { ExternalizableTest et = new ExternalizableTest(); ObjectOutput out = new ObjectOutputStream(new FileOutputStream( new File("test"))); out.writeObject(et); ObjectInput in = new ObjectInputStream(new FileInputStream(new File( "test"))); et = (ExternalizableTest) in.readObject(); System.out.println(et.content); out.close(); in.close(); } }

¿Se serializará la variable content? Bien, he mostrado la respuesta. Sí, el resultado de la ejecución es:

是的,我将会被序列化,不管我是否被transient关键字修饰

¿Por qué es esto? ¿No se decía que después de que una variable de clase es modificada por la palabra clave transient ya no puede serializarse?

Sabemos que en Java, la serialización de objetos se puede lograr implementando dos interfaces. Si se implementa la interfaz Serializable, toda la serialización se realizará automáticamente. Si se implementa la interfaz Externalizable, entonces nada se serializa automáticamente; es necesario especificar manualmente las variables a serializar en el método writeExternal, y esto no tiene relación con si están modificadas por transient. Por lo tanto, el segundo ejemplo produce el contenido inicializado de la variable content, no null.

Fuente: http://www.cnblogs.com/lanxuezaipiao/p/3369962.html