如果某个 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进行最简单的检验和控制。
再回来看看Eclipse的提示
在Eclipse中,提供两种方式让我们快速添加SerialVersionUid。
add default serial version ID:
Adds a default serial version ID to the selected type
Use this option to add a user-defined ID in combination with custom serialization code if the type did undergo structural change since its first release.
Default 值是1L, 在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就手工递增版本号。
add generated serial version ID:
Adds a generated serial version ID to the selected type
Use this option to add a compiler-generated ID if the type didnot undergo structural change since its first release.
根据类的结构产生的hash值。增减一个属性、方法等,都可能导致这个值产生变化。
适合场景
开发者认为每次修改类后就需要生成新的版本号,不想向下兼容,操作就是删除原有serialVesionUid声明语句,再自动生成一下。
个人认为default简单。第二种能够保证每次更改类结构后改变版本号,虽然看上去很cool,实际上让人很迷惑。
如何使用 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/