如果某个 class implements Serializable,Eclipse 会提示生成 serialVersionUID ,多数情况下,我都选择是。可这个东西到底是什么呢?
package com.home.demo; import java.io.Serializable; public class Item implements Serializable { private static final long serialVersionUID = 1L; private int data; public Item (int data) { this.data = data; } public int getData() { return data; } }
Eclipse 再次提醒我要有serialVersionUID 。 好吧,既然是测试,给他个值1。
写一个测试类,试试 serialize and deserialize Item
package com.home.demo; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class UIDTest { public void save2Disk(String fileName) throws IOException{ File file = new File(fileName); FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos); //set value to 101 Item serializeMe = new Item(101); oos.writeObject(serializeMe); oos.close(); System.out.println("done!"); } public void readFromDisk(String fileName) throws ClassNotFoundException, IOException{ FileInputStream fis = new FileInputStream(fileName); ObjectInputStream ois = new ObjectInputStream(fis); Item dto = (Item) ois.readObject(); System.out.println("data : " + dto.getData()); ois.close(); } /** * @param args * @throws IOException * @throws ClassNotFoundException */ public static void main(String[] args) { UIDTest test = new UIDTest(); String name = "D:/out.dat"; try{ // write file //test.save2Disk(name); //--1 test.readFromDisk(name); // --2 }catch(Exception e){ e.printStackTrace(); } } }
运行结果
101
完全正确!
看看D盘,有个文件out.dat. 关闭写文件,直接读取 out.dat
运行结果
101
试试把 serialVersionUID = 2L
private static final long serialVersionUID = 2L;
再运行
java.io.InvalidClassException: com.home.demo.Item; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
噢。。。。 出错了!
根据 Java document,
Serialization is for serializing instances, not classes. Static fields (methods are irrelevant since they are part of the class definition so they aren‘t serialized) will be reinitialized to whatever value they are set to when the class is loaded.
根据这个说法,Item不可能知道 serialVersionUID 的值,为什么会报错?
继续看文档!
好吧 serialVersionUID 属于例外,这个值的确“get serialized”.
ObjectOutputStream writes every time the value ofserialVersionUID to the output stream.
ObjectInputStream reads it back and if the value read from the stream does not agree with the serialVersionUID value in the current version of the class, then it throws the InvalidClassException. Moreover, if there is no serialVersionUID officially declared in the class to be serialized, compiler automatically adds it with a value generated based on the fields declared in the class.
假如你在机器A上serialize 了数据,然后送到B机器上deserialize ,需要一定的信息来帮忙确定数据的正确性。serialVersionUID 就是用于干这个活的。所以,Eclipse建议我们使用的serialVersionUID ,可以对serialization进行最简单的检验和控制。
如何正确使用 serialVersionUID ?
What you should do is to change serialVersionUID (for example increase it by 1 or make your IDE generate automatically a new value) every time there is some change in the definition of data stored in the class. For example if you change data types, variable names or add new data – hence every time you want to have ‘backward incompatibility’ for deserialization.
Reference
http://stackoverflow.com/questions/6429462/java-static-serialization-rules
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it
http://www.javablogging.com/what-is-serialversionuid/
http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/