遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题
a,什么叫序列化和反序列化
b,作用。为啥要实现这个 Serializable 接口,也就是为啥要序列化
c,serialVersionUID 这个的值到底是在怎么设置的,有什么用。有的是1L,有的是一长串数字,迷惑ing。
1、序列化和反序列化的概念
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
2、如何实现序列化
2.1、定义实体类实现Serializable接口
package com.example.dell.serializabledemo; import java.io.Serializable; public class SerializableInfo implements Serializable{ // private static final long serialVersionUID = 1L; private static int age = 20; private String name; private String sex; //transient:变量修饰符,用transient关键字标记的成员变量不参与序列化过程。 transient private String address; // private String addTip; 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 getAddress() { return address; } public void setAddress(String address) { this.address = address; } // public String getAddTip() { // return addTip; // } // // public void setAddTip(String addTip) { // this.addTip = addTip; // } @Override public String toString() { return "SerializableInfo{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", address='" + address + '\'' + ", age='" + age + '\'' + // ", addTip='" + addTip + '\'' + '}'; } }
2.2、main方法
package com.example.dell.serializabledemo; 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 SerializableTest { public static void main(String[] args) throws Exception { serialize(); SerializableInfo info = deserialize(); System.out.println(info.toString()); } /* * 序列化 * */ private static void serialize() throws IOException { SerializableInfo serializableInfo = new SerializableInfo(); serializableInfo.setName("张三"); serializableInfo.setSex("男"); serializableInfo.setAddress("北京"); //将serializableInfo对象存储到E盘文件中,完成序列化操作 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:/Serialize.txt"))); oos.writeObject(serializableInfo); System.out.println("对象序列化成功"); oos.close(); } /* * 反序列化 * */ private static SerializableInfo deserialize() throws Exception { //读取文件,完成反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:/Serialize.txt"))); SerializableInfo serializableInfo = (SerializableInfo) ois.readObject(); System.out.println("对象反序列化成功"); return serializableInfo; } }
运行结果
1、第一种:上面代码直接运行
同时会在E盘下生成Serialize.txt文件
2、第二种:静态的属性能不能被序列化和反序列化
先序列化对象到文件。这个对象是带静态变量的static。
public static void main(String[] args) throws Exception { serialize(); // SerializableInfo info = deserialize(); // System.out.println(info.toString()); }
现在修改实体类里面age的值,修改为18
然后运行反序列化代码
public static void main(String[] args) throws Exception { // serialize(); SerializableInfo info = deserialize(); System.out.println(info.toString()); }
运行结果
可以看到,刚刚序列化的20,没有读出来。读出来的是刚刚修改的18
所以,得出结论,这个静态static的属性,不序列化。
3、serialVersionUID 的作用和用法
先是单独执行序列化方法。生成文件。
然后,打开属性 addTip ,再次执行反序列化方法
抛异常
解释一下:
因为我再实体类里面是没有明确的给这个 serialVersionUID 赋值,但是,Java会自动的给我赋值的,
这个值跟这个实体类的属性相关计算出来的。
我保存的时候,也就是我序列化的时候,那时候还没有这个addTip属性呢,
所以,自动生成的serialVersionUID 这个值,
在我反序列化的时候Java自动生成的这个serialVersionUID值是不同的,他就抛异常啦。
再来一次,就是先序列化,这个时候,把 private static final long serialVersionUID = 1L; 这行代码的注释打开。那个addTip属性先注释掉
序列化之后,再把这个属性打开,再反序列化。
这个现象对我们有什么意义:
实体类实现了个Serializable接口,但是你没写这个 serialVersionUID 那么在后来扩展的时候,可能就会出现不认识旧数据的bug
所以,得到一个结论,就是在实现这个Serializable 接口的时候,一定要给这个 serialVersionUID 赋值,