transient 关键字
1,使用transient关键字向java虚拟机表明,transient变量不是对象的持久状态的一部分。
为了方便理解直接上例子
import lombok.Data; import java.io.Serializable; @Data public class Employee implements Serializable { private static final long serialVersionUID = 2624368016355021172L; private String firstName; private String lastName; /** * 使用transient关键字向java虚拟机表明, * transient变量不是对象的持久状态的一部分。 */ private transient String confidentialInfo; // Getter and Setter }
序列化
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class TransSerializationTest { public static void main(String[] args) { try { Employee emp = new Employee(); emp.setFirstName("Chen"); emp.setLastName("Shuaishuai"); emp.setConfidentialInfo("password"); System.out.println("Read before Serialization:"); System.out.println("firstName: " + emp.getFirstName()); System.out.println("lastName: " + emp.getLastName()); System.out.println("confidentialInfo: " + emp.getConfidentialInfo()); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("chenss.txt")); //Serialize the object oos.writeObject(emp); oos.close(); } catch (Exception e) { System.out.println(e); } } }
反序列化
import java.io.FileInputStream; import java.io.ObjectInputStream; public class TransDeSerializationTest { public static void main(String[] args) { try { ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("chenss.txt")); //Read the object back Employee readEmpInfo = (Employee) ooi.readObject(); System.out.println("Read From Serialization:"); System.out.println("firstName: " + readEmpInfo.getFirstName()); System.out.println("lastName: " + readEmpInfo.getLastName()); System.out.println("confidentialInfo: " + readEmpInfo.getConfidentialInfo()); ooi.close(); } catch (Exception e) { System.out.println(e); } } }
运行序列化与反序列化后会有如下的输出:
Read From Serialization: firstName: Chen lastName: Shuaishuai confidentialInfo: null
发现添加了关键字transient关键字后对象的相对应的属性是没有序列化的。也就是说当我们不需要对应的属性进行序列化的时候就可以使用该关键字。
2,final关键字修饰的属性添加transient关键字
那接下来我们看看在使用final关键后会有什么样的变化。在属性中添加一个String类型的属性和Logger的属性,先上代码:
import lombok.Data; import org.apache.log4j.Logger; import org.junit.Test; import java.io.Serializable; @Data public class Employee implements Serializable { private static final long serialVersionUID = 2624368016355021172L; private String firstName; private String lastName; //final field 1 public final transient String confidentialInfo = "password"; //final field 2 private final transient Logger logger = Logger.getLogger("demo"); //Getter and Setter }
序列化
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class TransSerializationTest { public static void main(String[] args) { try { Employee emp = new Employee(); emp.setFirstName("Chen"); emp.setLastName("Shuaishuai"); System.out.println("Read before Serialization:"); System.out.println("firstName: " + emp.getFirstName()); System.out.println("lastName: " + emp.getLastName()); System.out.println("confidentialInfo: " + emp.getConfidentialInfo()); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("chenss.txt")); //Serialize the object oos.writeObject(emp); oos.close(); } catch (Exception e) { System.out.println(e); } } }
反序列化:
import java.io.FileInputStream; import java.io.ObjectInputStream; public class TransDeSerializationTest { public static void main(String[] args) { try { ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("chenss.txt")); //Read the object back Employee readEmpInfo = (Employee) ooi.readObject(); System.out.println("Read From Serialization:"); System.out.println("firstName: " + readEmpInfo.getFirstName()); System.out.println("lastName: " + readEmpInfo.getLastName()); System.out.println("confidentialInfo: " + readEmpInfo.getConfidentialInfo()); System.out.println("logger: " + readEmpInfo.getLogger()); ooi.close(); } catch (Exception e) { System.out.println(e); } } }
序列化与反序列化后的输出:
Read From Serialization: firstName: Chen lastName: Shuaishuai confidentialInfo: password logger: null
从输出结果中我们可以看到:添加final关键字的属性中 confidentialInfo 进行了序列化,而logger没有进行序列化。
很奇怪。我们已将confidentialInfo标记为transient;字段仍然被序列化了。而对于类似的声明,logger却没有被序列化。为什么?
原因是,无论何时将任何final字段/引用计算为“常量表达式”,JVM都会对其进行序列化,忽略transient关键字的存在。
在上面的例子中,值password是一个常量表达式,logger demo的实例是引用。因此,根据规则,confidentialInfo被持久化,而logger没有被持久化。
您是否在想,如果我从两个字段中删除transient呢?那么,实现可序列化引用的字段将保持不变。因此,如果在上面的代码中删除transient,String(实现Serializable)将被持久化;而Logger(不实现Serializable)将不会被持久化,并且将会抛出异常java.io.NotSerializableException。
如果希望持久保存不可序列化字段的状态,那么可以使用readObject()和writeObject()方法。writeObject()/readObject()通常在内部链接到序列化/反序列化机制中,因此会自动调用。
了解更多:点击
原文:https://www.jianshu.com/p/2911e5946d5c
这篇文章几乎全来自于原文,这里学习了记录一下。感谢作者
说明serialVersionUID
serialVersionUID是Serializable类的通用版本标识符。反序列化使用这个数字来确保加载的类与序列化的对象完全对应。如果没有找到匹配,则抛出InvalidClassException。|।1。始终将它作为一个字段包含,例如:"private static final long serialVersionUID = 7526472295622776147L: "即使在类的第一个版本中也要包含这个字段,以提醒它的重要性。不要在未来的版本中更改此字段的值,除非你有意地对类进行更改,使其与旧的序列化对象不兼容。如有需要,请遵循上述指导方针