Java序列化之serialVersionUID
2016-11-17 10:12
423 查看
一、问题
1、声明serialVersionUID的作用是什么?
2、JVM如何通过serialVersionUID属性来确定是否可反序列化,怎么起作用的?
3、继承java.io.Serializable接口后不声明serialVersionUID属性Eclipse会发出警告,怎么解决?
4、继承java.io.Serializable接口后不声明serialVersionUID属性,Java是如何处理序列化与反序列化的?
5、不声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
6、声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
7、如果没有定义serialVersionUID,缺省的serialVersionUID值是怎么确定的?什么时候确定的(编译还是运行时)?缺省的serialVersionUID什么时候会发生变化?我们写的类是否应该推荐定义serialVersionUID?
8、显示定义serialVersionUID的两种用途
二、解决问题
1、声明serialVersionUID的作用是什么?
Java在类序列化与反序列化过程中,通过serialVersionUID来确定是否可进行反序列化。
2、JVM如何通过serialVersionUID属性来确定是否可反序列化,怎么起作用的?
类在序列化时,Java根据serialVersionUID标识将对象转成字节序列存储至硬件硬盘或传输在网络上;在进行反序列化时,JVM把字节流中的serialVersionUID与本地类的serialVersionUID进行比较,如果相同即可进行反序列号,否则会出现序列化版本不一致异常(InvalidCastException)。
3、继承java.io.Serializable接口后不声明serialVersionUID属性Eclipse会发出警告,怎么解决?
当类实现 java.io.Serializable
时,说明这个类可被序列化,这时eclipse会发出警告(The serializable class Test does not declare a static final serialVersionUID field of type long),要解决这个警告必须声明属性serialVersionUID并且给属性赋值。serialVersionUID的生成方式有两种:一是缺省的1L(private
static final long serialVersionUID = 1L;);另一个是根据类名、接口名、成员方法及属性来生成一个64位的哈希字段,如:(private static final long serialVersionUID = -344227642091683711L;);
移动鼠标到类名上或单击类名:
Add default serial version ID
Add generated serial version ID
4、继承java.io.Serializable接口后不声明serialVersionUID属性,Java是如何处理序列化与反序列化的?
若没有显示的去声明这个属性,Java序列化机制会根据编译的class的类名、方法名等因素自动生成一个serialVersionUID用于反序列化比较,这种情况下class没有发生变化的时候(类增加注释或空格)无论编译任何次数,此属性的值是不会发生变化的。
5、不声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
序列化后文件:
6、声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
此处序列化代码见上面。
序列化后文件:
7、如果没有定义serialVersionUID,缺省的serialVersionUID值是怎么确定的?什么时候确定的(编译还是运行时)?缺省的serialVersionUID什么时候会发生变化?我们写的类是否应该推荐定义serialVersionUID?
在序列化运行时将基于该类的各个方面计算该类的默认serialVersionUID值。缺省的serialVersionUID完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同;在类被改变(不包含改变注释或空格回车等)后重新编译后,serialVersionUID会发生变化。强烈建议所有可序列化的类都显示声明serialVersionUID值,因为计算默认的serialVersionUID对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的InvalidClassException
;为保证serialVersionUID值跨不同Java编译器实现的一致性,序列化类必须声明一个明确的serialVersionUID值;还强烈建议使用private修饰符显示声明serialVersionUID,因为这种声明仅应用于直接声明类,作为继承成员没有用处。数组类不能声明一个明确的serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配serialVersionUID值的要求。
8、显示定义serialVersionUID的两种用途
a.在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
b.当你序列化了一个类实例后,希望更改一个字段或添加一个字段,不设置serialVersionUID,所做的任何更改都将导致无法反序列化旧的实例,并在反序列化时抛出一个异常。如果你添加了serialVersionUID,在反序列化旧实例时,新添加或更改的字段值将设为初始化值,字段被删除将不设置。
三、注意事项
1、序列化时,只对对象的状态进行保存,不管对象的方法;
2、当一个父类实现序列化,子类自动实现序列化,不需要显示实现java.io.Serializable接口;
3、当一个对象的实例变量引用其它对象,序列化该对象时也把引用对象进行序列化。
1、声明serialVersionUID的作用是什么?
2、JVM如何通过serialVersionUID属性来确定是否可反序列化,怎么起作用的?
3、继承java.io.Serializable接口后不声明serialVersionUID属性Eclipse会发出警告,怎么解决?
4、继承java.io.Serializable接口后不声明serialVersionUID属性,Java是如何处理序列化与反序列化的?
5、不声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
6、声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
7、如果没有定义serialVersionUID,缺省的serialVersionUID值是怎么确定的?什么时候确定的(编译还是运行时)?缺省的serialVersionUID什么时候会发生变化?我们写的类是否应该推荐定义serialVersionUID?
8、显示定义serialVersionUID的两种用途
二、解决问题
1、声明serialVersionUID的作用是什么?
Java在类序列化与反序列化过程中,通过serialVersionUID来确定是否可进行反序列化。
2、JVM如何通过serialVersionUID属性来确定是否可反序列化,怎么起作用的?
类在序列化时,Java根据serialVersionUID标识将对象转成字节序列存储至硬件硬盘或传输在网络上;在进行反序列化时,JVM把字节流中的serialVersionUID与本地类的serialVersionUID进行比较,如果相同即可进行反序列号,否则会出现序列化版本不一致异常(InvalidCastException)。
3、继承java.io.Serializable接口后不声明serialVersionUID属性Eclipse会发出警告,怎么解决?
当类实现 java.io.Serializable
时,说明这个类可被序列化,这时eclipse会发出警告(The serializable class Test does not declare a static final serialVersionUID field of type long),要解决这个警告必须声明属性serialVersionUID并且给属性赋值。serialVersionUID的生成方式有两种:一是缺省的1L(private
static final long serialVersionUID = 1L;);另一个是根据类名、接口名、成员方法及属性来生成一个64位的哈希字段,如:(private static final long serialVersionUID = -344227642091683711L;);
移动鼠标到类名上或单击类名:
Add default serial version ID
Add generated serial version ID
4、继承java.io.Serializable接口后不声明serialVersionUID属性,Java是如何处理序列化与反序列化的?
若没有显示的去声明这个属性,Java序列化机制会根据编译的class的类名、方法名等因素自动生成一个serialVersionUID用于反序列化比较,这种情况下class没有发生变化的时候(类增加注释或空格)无论编译任何次数,此属性的值是不会发生变化的。
5、不声明serialVersionUID属性,对象序列化后,对象属性声明发生变化,这时可以反序列化回来么?
序列化前Java类 SmallDog.java(未显示声明serialVersionUID属性) |
public class SmallDog implements Serializable{ private String name; private Double weight; private int age; public SmallDog() {} public SmallDog(String name, Double weight, int age) { this.name = name; this.weight = weight; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getWeight() { return weight; } public void setWeight(Double weight) { this.weight = weight; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "SmallDog{" + "name='" + name + '\'' + ", weight=" + weight + ", age=" + age + '}'; } } |
序列化类代码片段 |
public void testSeralizableSmallDog(){ SmallDog smallDog = new SmallDog("小白", 4.0, 1); try { FileOutputStream fos = new FileOutputStream("seralizable.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(smallDog); oos.flush(); oos.close(); } catch (IOException e) { e.printStackTrace(); } } |
以上类增加一个属性重新编译SmallDog.java |
public class SmallDog implements Serializable{ private String name; private Double weight; private int age; private String sex; public SmallDog() { } public SmallDog(String name, Double weight, int age) { this.name = name; this.weight = weight; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getWeight() { return weight; } public void setWeight(Double weight) { this.weight = weight; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "SmallDog{" + "name='" + name + '\'' + ", weight=" + weight + ", age=" + age + '}'; } } |
反序列化代码片段 |
public void deserializeSmallDog(){ try { SmallDog smallDog; FileInputStream fis = new FileInputStream(new File("seralizable.txt")); ObjectInputStream ois = new ObjectInputStream(fis); smallDog = (SmallDog)ois.readObject(); System.out.println(smallDog.toString()); ois.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } |
输出结果 |
java.io.InvalidClassException: com.smalldog.implseralizable.SmallDog; local class incompatible: stream classdesc serialVersionUID = -3046572760386773397, local class serialVersionUID = 359715241838742995 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) at com.smalldog.SerializableTestCase.deserializeSmallDog(SerializableTestCase.java:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) |
序列化前Java类 SmallDog.java(显示声明serialVersionUID属性) |
public class SmallDog implements Serializable{ private static final long serialVersionUID = 1L; private String name; private Double weight; private int age; public SmallDog() {} public SmallDog(String name, Double weight, int age) { this.name = name; this.weight = weight; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getWeight() { return weight; } public void setWeight(Double weight) { this.weight = weight; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "SmallDog{" + "name='" + name + '\'' + ", weight=" + weight + ", age=" + age + '}'; } } |
序列化后文件:
以上类增加一个属性重新编译SmallDog.java |
public class SmallDog implements Serializable{ private static final long serialVersionUID = 1L; private String name; private Double weight; private int age; private String sex; public SmallDog() { } public SmallDog(String name, Double weight, int age) { this.name = name; this.weight = weight; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getWeight() { return weight; } public void setWeight(Double weight) { this.weight = weight; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "SmallDog{" + "name='" + name + '\'' + ", weight=" + weight + ", age=" + age + '}'; } } |
输出结果 |
SmallDog{name='小白', weight=4.0, age=1} |
在序列化运行时将基于该类的各个方面计算该类的默认serialVersionUID值。缺省的serialVersionUID完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同;在类被改变(不包含改变注释或空格回车等)后重新编译后,serialVersionUID会发生变化。强烈建议所有可序列化的类都显示声明serialVersionUID值,因为计算默认的serialVersionUID对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的InvalidClassException
;为保证serialVersionUID值跨不同Java编译器实现的一致性,序列化类必须声明一个明确的serialVersionUID值;还强烈建议使用private修饰符显示声明serialVersionUID,因为这种声明仅应用于直接声明类,作为继承成员没有用处。数组类不能声明一个明确的serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配serialVersionUID值的要求。
8、显示定义serialVersionUID的两种用途
a.在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
b.当你序列化了一个类实例后,希望更改一个字段或添加一个字段,不设置serialVersionUID,所做的任何更改都将导致无法反序列化旧的实例,并在反序列化时抛出一个异常。如果你添加了serialVersionUID,在反序列化旧实例时,新添加或更改的字段值将设为初始化值,字段被删除将不设置。
三、注意事项
1、序列化时,只对对象的状态进行保存,不管对象的方法;
2、当一个父类实现序列化,子类自动实现序列化,不需要显示实现java.io.Serializable接口;
3、当一个对象的实例变量引用其它对象,序列化该对象时也把引用对象进行序列化。
相关文章推荐
- java序列化serialVersionUID
- 类接口java序列化作用以及 serialVersionUID
- Java中序列化的serialVersionUID作用
- java序列化和serialVersionUID
- 深入理解Java序列化中的SerialVersionUid
- java对序列化serialVersionUID的处理分析
- Java序列化机制和原理以及在eclipse中自动生成serialVersionUID
- java中序列化的serialVersionUID解释
- serialVersionUID的作用、java的序列化/反序列化
- 深入理解Java序列化中的SerialVersionUid
- Java序列化和serialVersionUID
- Java中为什么实现了Serializable接口就具备了被序列化的能力以及serialVersionUID的作用
- java 序列化serialVersionUID 作用
- java中序列化的serialVersionUID解释
- java对序列化serialVersionUID的处理分析
- java序列化的serialVersionUID
- java序列化作用以及 serialVersionUID
- JAVA中,对象的序列化与serialVersionUID
- Java序列化中的serialVersionUID有什么用?
- Java____序列化private static final long serialVersionUID的作用