1.什么是序列化和反序列化java
序列化就是将java对象转成字节序列的过程;反序列化就是将字节序列转成java对象的过程。算法
java中,序列化的目的一种是须要将对象保存到硬盘上,一种是对象须要在网络中传输。json
2.序列化和反序列化的方式网络
序列化和反序列化有不少种方式,如JDK类库中提供的序列化API、经常使用的json工具类等。本篇博客使用JDK提供的序列化API进行演示。重点说明serialVersionUID的做用。工具
假设如今有一个Student类,咱们要对Student类进行序列化操做测试
①该类必须实现Serializable接口this
public class Student implements Serializable{ private static final long serialVersionUID = -595470438262181967L; private String name ; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
②在main方法中执行序列化和反序列化操做spa
public static void main(String[] args) throws Exception { //序列化 OutputStream os = new FileOutputStream(new File("D://student.txt")); ObjectOutputStream oos = new ObjectOutputStream(os); Student student = new Student(); student.setName("张三"); student.setSex("男"); oos.writeObject(student); //反序列化 InputStream is = new FileInputStream(new File("D://student.txt")); ObjectInputStream ois = new ObjectInputStream(is); Student student1 = new Student(); student1 = (Student) ois.readObject(); System.out.println(student1.getName()); }
输出结果:张三code
即student1对象在反序列化时进行了赋值对象
3.为何要serialVersionUID
serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量。
(1)下面进行测试,若是没有serialVersionUID会出现什么?
①去掉Student类中的serialVersionUID属性。执行main方法,结果显示序列化成功!输出张三
②修改Student类,在Student类中添加number字段
public class Student implements Serializable{ private String name ; private String sex; private String number; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } }
不执行序列化方法,只执行反序列化方法,结果出现异常:
Exception in thread "main" java.io.InvalidClassException: com.iot.study.serialize.Student; local class incompatible: stream classdesc serialVersionUID = -595470438262181967, local class serialVersionUID = -4254220179260112271 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:621) 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.iot.study.serialize.Client.main(Client.java:35)
意思是原来序列化的时候(没有指定serialVersionUID)硬盘存的class的 serialVersionUID = -595470438262181967,而当前class的serialVersionUID = -4254220179260112271。 两者不同,没法反序列化。
缘由分析:
serialVersionUID没有指定时,java编译器会自动给这个class进行一个摘要算法,相似于指纹算法,只要这个文件 多一个空格,获得的UID就会大相径庭的,能够保证在这么多类中,这个编号是惟一的。因此,添加了一个number字段后,因为没有显指定 serialVersionUID,编译器又为咱们生成了一个UID,固然和前面保存在文件中的那个不会同样了,因而就出现了2个序列化版本号不一致的错误。
(2)指定serialVersionUID测试
若是为Student类显示的指定serialVersionUID,那么在序列化和反序列化的时候,即便修改了Student类中的部份内容,也能序列化成功。
4.serialVersionUID的取值
serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。若是对类的源代码做了修改,再从新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值彻底依赖于Java编译器的实现,对于同一个类,用不一样的Java编译器编译,有可能会致使不一样的 serialVersionUID,也有可能相同。为了提升serialVersionUID的独立性和肯定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。
显式地定义serialVersionUID有两种用途: 一、 在某些场合,但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备相同的serialVersionUID; 二、 在某些场合,不但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备不一样的serialVersionUID。