serialVersionUID按字面上意思来理解是序列化版本号,用以下例子可以得出serialVersionUID的实际作用
Person类:
public class Person implements Serializable{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
Test测试类:
public class Test {
public static void main(String[] args) {
try {
Serialize();
Person person = Deserialize();
System.out.println(person);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void Serialize() throws FileNotFoundException, IOException{
Person person = new Person("jack", 25);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:person.txt"));
oos.writeObject(person);
System.out.println("Person类序列化成功");
oos.flush();
oos.close();
}
private static Person Deserialize() throws FileNotFoundException, IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:person.txt"));
Person person = (Person) ois.readObject();
System.out.println("Person类反序列化成功");
ois.close();
return person;
}
}
①在Person类没有添加serialVersionUID时,先执行Serialize()方法,运行结果:
Person类序列化成功
②在Person新加sex属性:
public class Person implements Serializable{
private String name;
private int age;
private String sex;
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
③这时候再执行Deserialize()方法,抛出异常:
java.io.InvalidClassException: one.Person; local class incompatible: stream classdesc serialVersionUID = -933002983885753244,
local class serialVersionUID = -3251846478824884491
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at one.Test.Deserialize(Test.java:33)
at one.Test.main(Test.java:15)
意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。
可以看到,我们在Person类中没有指定Person类的serialVersionUID属性,所以java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件 多一个空格,得到的UID就会截然不同的,这样子就可以保证在这么多类中,这个编号是唯一的。
总的来说,serialVersionUID属性相当于Java对象的序列化版本号(类似于人类指纹),编译器会根据这个值来判断能否反序列化,在我们没指定对象的serialVersionUID属性时,对象也会有一个自动生成的serialVersionUID属性。
因此,如果我们需要对象在序列化后改变不影响反序列化,就必须指定实体类的serialVersionUID属性。
修改后的Person类:
public class Person implements Serializable{
private static final long serialVersionUID = -3251846478824884491L;
private String name;
private int age;
private String sex;
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
程序运行结果:
Person类序列化成功
Person类反序列化成功
Person [name=jack, age=25, sex=男]