什么是java序列化与反序列化
- 序列化:把java对象通过某种方式写入磁盘,或者传输给其他网络节点。即将对象转为二进制的过程。
- 反序列化:把磁盘中的文件,或者网络节点的数据通过某种方式转为java对象。即将二进制转为对象。
java序列化的使用场景
通过上面序列化的定义,可以初步了解序列化的使用场景。
- 将内存中的数据保存到磁盘或者数据库中。
- 需要在网络中传输对象。
- 想通过RMI传输对象。
java序列化实例
下面直接上代码,通过代码实例学习如何实现序列化。
创建实体
为了深入理解实现序列化与反序列化,首先创建几个实体。
User.java、Person.java、OtherInfo.java,他们的关系是User.java中引用了OtherInfo.java,User.java继承了Person.java。三个实体都有get/set/toString方法,方便查看测试效果。
为何创建创建这三个实体呢?
- 测试是否能序列化父类的数据
- 测试是否能序列化引用类型的数据
代码如下:
User.java
package org.ludk.serializable;
import java.io.Serializable;
/**
* @author ludengke
* @title: User
* @projectName springcloud-demo
* @description: TODO
* @date 2021/10/2420:14
*/
public class User extends Person {
private String name;
private int age;
private OtherInfo otherInfo;
public User(String name, int age, OtherInfo otherInfo) {
this.name = name;
this.age = age;
this.otherInfo = otherInfo;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", otherInfo=" + otherInfo +
'}'+
super.toString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public OtherInfo getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(OtherInfo otherInfo) {
this.otherInfo = otherInfo;
}
}
OtherInfo.java
package org.ludk.serializable;
import java.io.Serializable;
/**
* @author ludengke
* @title: OtherInfo
* @projectName springcloud-demo
* @description: TODO
* @date 2021/10/2420:15
*/
public class OtherInfo {
private String ph;
private String address;
public OtherInfo(String ph, String address) {
this.ph = ph;
this.address = address;
}
@Override
public String toString() {
return "OtherInfo{" +
"ph='" + ph + '\'' +
", address='" + address + '\'' +
'}';
}
public String getPh() {
return ph;
}
public void setPh(String ph) {
this.ph = ph;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Person.java
package org.ludk.serializable;
import java.io.Serializable;
/**
* @author ludengke
* @title: Person
* @projectName springcloud-demo
* @description: TODO
* @date 2021/10/2420:18
*/
public class Person {
private String head;
private String body;
@Override
public String toString() {
return "Person{" +
"head='" + head + '\'' +
", body='" + body + '\'' +
'}';
}
public String getHead() {
return head;
}
public void setHead(String head) {
this.head = head;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
java序列化与反序列化工具类
SerializableUtil.java
package org.ludk.serializable;
import java.io.*;
/**
* @author ludengke
* @title: SerializableUtil
* @projectName springcloud-demo
* @description: 克隆的工具类
* @date 2021/10/2420:24
*/
public class SerializableUtil {
/**
*@Description 保存对象,序列化
*@Param [object]
*@Return void
*@Author ludengke
*@Date 2021/10/24
*@Time 20:29
*/
public static void saveObject(Object object){
ObjectOutputStream objectOutputStream=null;
FileOutputStream fileOutputStream=null;
try {
fileOutputStream=new FileOutputStream("D:\\work\\test\\serializable\\writeToFile.txt");
objectOutputStream=new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*@Description 读对象,反序列化
*@Param []
*@Return java.lang.Object
*@Author ludengke
*@Date 2021/10/24
*@Time 20:36
*/
public static Object readObject(){
ObjectInputStream objectInputStream=null;
FileInputStream fileInputStream=null;
try {
fileInputStream=new FileInputStream("D:\\work\\test\\serializable\\writeToFile.txt");
objectInputStream=new ObjectInputStream(fileInputStream);
return objectInputStream.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
测试类
TestSerializable.java
package org.ludk.serializable;
/**
* @author ludengke
* @title: TestSerializable
* @projectName springcloud-demo
* @description: TODO
* @date 2021/10/2420:19
*/
public class TestSerializable {
public static void main(String[] args) {
User user=new User("卢**",35,new OtherInfo("1834156****","北京海淀"));
user.setHead("大头");
user.setBody("小身体");
//打印序列化前的对象
System.out.println(user);
//序列化
SerializableUtil.saveObject(user);
//反序列化
User readFromFile=(User) SerializableUtil.readObject();
//打印通过反序列化生成的对象
System.out.println(readFromFile);
}
}
测试与修正的过程
- 运行TestSerializable.java的main方法,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=51808:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
java.io.NotSerializableException: org.ludk.serializable.User
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.ludk.serializable.User
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1631)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at org.ludk.serializable.SerializableUtil.readObject(SerializableUtil.java:55)
at org.ludk.serializable.TestSerializable.main(TestSerializable.java:18)
Caused by: java.io.NotSerializableException: org.ludk.serializable.User
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
null
Process finished with exit code 0
java.io.NotSerializableException: org.ludk.serializable.User的意思很明显,org.ludk.serializable.User不能被实例化。
结论一:被序列化的对象实体需要实现java.io.Serializable接口,否则会抛NotSerializableException异常
所以让org.ludk.serializable.User实现serializable接口,被调整的部分代码如下:
public class User extends Person implements Serializable {
- 再次跑测试类,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52041:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
java.io.NotSerializableException: org.ludk.serializable.OtherInfo
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.ludk.serializable.OtherInfo
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1631)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2341)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2265)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2123)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at org.ludk.serializable.SerializableUtil.readObject(SerializableUtil.java:55)
at org.ludk.serializable.TestSerializable.main(TestSerializable.java:18)
Caused by: java.io.NotSerializableException: org.ludk.serializable.OtherInfo
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
null
Process finished with exit code 0
java.io.NotSerializableException: org.ludk.serializable.OtherInfo
这段错误说明OtherInfo也要实现serializable接口。
结论二:引用对象的实体类也需要实现java.io.Serializable接口,否则抛NotSerializableException异常。
调整的部分代码如下:
public class OtherInfo implements Serializable{
- 再次跑测试类,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52382:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='null', body='null'}
Process finished with exit code 0
这次不抛异常了,但是父类Person.java的属性没有被序列化,head和body为空。
结论三:父类也要实现java.io.Serializable接口,否则父类的属性不会被序列化。
调整的部分代码如下:
public class Person implements Serializable{
- 再次跑测试类,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52500:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
Process finished with exit code 0
完美了。
听说静态变量不会被序列化( static,transient),我就不试了。
结论四:静态变量不会被序列化( static,transient)
序列化ID
序列化时一般会加入下面的代码(我没加):
private static final long serialVersionUID = 1L;
它决定着是否能够成功反序列化!
java的序列化机制是通过判断运行时类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
因为我测试的时候是用一个实体序列化和反序列化,所以看不出效果。
java序列化总结
-
被序列化的对象实体需要实现java.io.Serializable接口,否则会抛NotSerializableException异常。
-
引用对象的实体类也需要实现java.io.Serializable接口,否则抛NotSerializableException异常
-
父类也要实现java.io.Serializable接口,否则父类的属性不会被序列化。
-
静态变量不会被序列化( static,transient)
-
序列化ID应自己写,尽量不自动生成,因为序列化与反序列化的序列化ID应该保持一致