什么是序列化与反序列化?
序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。这个过程称为序列化。通俗来说就是将数据结构或对象转换成二进制串的过程
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
序列化用途
①、在分布式系统中,此时需要把对象在网络上传输,就得把对象数据转换为二进制形式,需要共享的数据的 JavaBean 对象,都得做序列化。
②、服务器钝化:如果服务器发现某些对象好久没活动了,那么服务器就会把这些内存中的对象持久化在本地磁盘文件中(Java对象转换为二进制文件);如果服务器发现某些对象需要活动时,先去内存中寻找,找不到再去磁盘文件中反序列化我们的对象数据,恢复成 Java 对象。这样能节省服务器内存
java实现序列化
通过这个两个对象进行序列化操作
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
其中对应方法(这里用到读取Object)
实现 java.io.Serializable 接口
package io.domain;
import java.io.Serializable;
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 + "]";
}
}
测试
package io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import io.domain.Person;
public class DriveTest2 {
public static void main(String[] args) throws Exception {
Person person = new Person("张三", 11);
//当前工程根目录
FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(person); //序列化
oos.close();
FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject(); //反序列化
if (object instanceof Person) {
Person person2 = (Person) object;
System.out.println(person2.toString());
}
fis.close();
}
}
测试结果
Person [name=张三, age=11]
java实现序列化注意事项
不实现 java.io.Serializable 接口
抛出异常
Exception in thread "main" java.io.NotSerializableException: io.domain.Person
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at io.DriveTest2.main(DriveTest2.java:18)
transient 字段不序列化
去除不需要序列化的字段
package io.domain;
import java.io.Serializable;
public class Person implements Serializable {
public static String staticString = "staticString";
private transient 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 + "]";
}
}
测试
package io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import io.domain.Person;
public class DriveTest2 {
public static void main(String[] args) throws Exception {
Person person = new Person("张三", 11);
System.out.println(Person.staticString);
//当前工程根目录
FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(person); //序列化
oos.close();
FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject(); //反序列化
if (object instanceof Person) {
Person person2 = (Person) object;
System.out.println(person2.toString());
System.out.println(person2.staticString);
}
fis.close();
}
}
测试结果
staticString
Person [name=null, age=11]
staticString
serialVersionUID 字段作用
序列化版本问题,在完成序列化操作后,由于项目的升级或修改,可能我们会对序列化对象进行修改,比如增加某个字段,那么我们在进行反序列化就会报错:
Exception in thread "main" java.io.InvalidClassException: io.domain.Person; local class incompatible: stream classdesc serialVersionUID = -14444189870184359, local class serialVersionUID = 155460768953663504
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at io.DriveTest2.main(DriveTest2.java:21)
解决办法:在 JavaBean 对象中增加一个 serialVersionUID 字段,用来固定这个版本,无论我们怎么修改,版本都是一致的,就能进行反序列化了
private static final long serialVersionUID = 1L;