序列化,即把一个对象内容,转换成字节序列。反序列化,将字节序列恢复成一个对象的过程。若一个对象需要序列化,实现 Serializable 接口。一个例子。
public class SerializableMain {
public static void main(String[] args) {
User user=new User("name_one","age_one","height_one");
try {
File file=new File("C:\\Users\\name\\Desktop\\DemoFile");
if(!file.exists()) {
file.createNewFile();
}
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(user);
oos.close();
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
User userTemp=(User)ois.readObject();
System.out.println(userTemp.toString());
}catch(Exception e) {
e.printStackTrace();
}
}
}
User对象,实现Serializable接口才可以将该对象序列化和反序列化。将对象序列化输出到文件流时,如果未实现Serializable接口,将抛出异常。
java.io.NotSerializableException: User
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at SerializableMain.main(SerializableMain.java:19)
从文件中反序列化一个对象时,(先实现接口完成序列化写入,再去掉接口),如果未实现Serializable接口,将抛出异常。
java.io.InvalidClassException: User; class invalid for deserialization
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at SerializableMain.main(SerializableMain.java:24)
transient修饰的属性,不会被序列化和反序列化。序列化时,忽略该属性写入字节数组,反序列化时,不会读取属性。在User类的age属性加上该修饰。反序列化时,打印结果将是null。
User [name=name_one, age=null, height=height_one]
静态字段不会被序列化。在User类加上一个静态字段address=shanghai,先进行一次User对象序列化输出,然后,将该字段改为beijing,注释掉序列化部分,只进行反序列化。这时,反序列化address值并不是shanghai,而是beijing。说明第一次序列化时,并没有将静态字段写入。
serialVersionUID的作用。不加该项时,序列化,将会采用Java自动生成的值,正常情况下,序列化和反序列化是没问题的。如果在User类新增一个字段weight,注释掉序列化的代码,直接进行反序列化,将抛出异常。
java.io.InvalidClassException: User; local class incompatible:
stream classdesc serialVersionUID = 4765874944071207273,
local class serialVersionUID = -4975271451414878760
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at SerializableMain.main(SerializableMain.java:21)
反序列化serialVersionUID和当前User对象的serialVersionUID不同,因为我该值是Java自动生成的,根据该类属性计算生成,保存文件的内容是没有weight属性的,因此,生成的serialVersionUID不同。User类中加上serialVersionUID字段。对字段属性的修改再反序列化将不会报错。
private static final long serialVersionUID = 1L;
这次不改属性,当serialVersionUID=1L序列化完成后,注释掉序列化代码,改serialVersionUID=2344,进行反序列化,同样将报serialVersionUID不相等的异常,
java.io.InvalidClassException: User; local class incompatible:
stream classdesc serialVersionUID = 1,
local class serialVersionUID = 2344
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
因此,serialVersionUID值一定要自己写上,且不要随便改变,不要让Java自动生成。否则,在更新对象属性(Java自动生成会改变),再去进行反序列化时,将无法识别出老数据。
任重而道远
网友评论