一、首先来看看序列化和反序列化是用来干什么的?
我们知道对象并不能直接在端与端之间进行通信,因此如果一个对象又需要进行端对端的通信怎么办呢?这时候有人就想出了在发送端把对象先转成可以进行传输的字节,在接收端再通过把字节转化成对象的方式进行传输。这种将对象转成字节的方式就是序列化,而将字节转回对象的方式则是反序列化。
一般序列化解决的是将对象持久化到磁盘中,或者对象在网络中传输的问题。
二、下面通过代码实现对象存储到磁盘与从磁盘中读取来理解序列化反序列化
1. 先键一个Cat类
public class Cat implements Serializable{
/**
* serialVersionUID
*/
private static final long serialVersionUID = 4669394576337676835L;
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
注意:如果不序列化是无法将对象持久化到磁盘的,而序列化对象只要对象实现Serializable接口就行,若不实现序列化接口就会报如下错误
java.io.NotSerializableException: com.java.base.bean.Cat
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.java.base.io.SerializableTest.main(SerializableTest.java:18)
2. 建一个SerializableTest类,实现对象序列化存储到磁盘中
public class SerializableTest {
public static void main(String[] args) {
try {
//对象将写入D盘下名为cat.txt的文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/cat.txt"));
Cat cat = new Cat();
cat.setAge(2);
cat.setName("阿斗");
//将对象写入文件中
oos.writeObject(cat);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.建一个DeserializableTest类,将序列化数据读出,并且转成Cat对象
public class DeserializableTest {
public static void main(String[] args) {
try {
//读取之前序列化的文件cat.txt
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/cat.txt"));
//将读取的数据转为Cat对象的形式
Cat cat = (Cat) ois.readObject();
System.out.println("cat age:"+cat.getAge() + " | cat name:"+cat.getName());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
如果,我们的对象有些属于隐私信息,不想将他序列化怎么办,使用瞬时变量transient,如下表示不会将age属性序列化。
private transient int age;
当然我们还可以使用另一种方式阻止将我们的隐私信息序列化,那就是使用实现Externalizable代替Serializable这个方法来解决。如果我们有一些特殊的需求也可以使用这个Externalizable 来实,Externalizable对于Serializable增加了两个方法,writeObject和readObject,这两个方法会优先与其他方法先执行。
三、虽然序列化那么好,但是万物皆难完美,下面说一下关于序列化的一些不足之处
1、序列化后对象变得不再灵活。
如:在web项目组中提供的一个类Cat的接口服务,在API包调用方法获取这个类的属性的时候,在本API创建的Cat中,将原本应该是私有域的age,变成公有域的age。
private int age;public int age
2、如果序列化的类中进行了修改,那么反序列化的类也要同步修改,否则容易出现bug。
如:在web中提供的Cat类的接口服务,Cat新增了一个属性sex,如果API的反序列化还是使用原来的序列化格式的话,就会爆出异常,无法接收到新的属性sex。
3、系统的序列化反序列化是比较耗时的,例如使用Gson对象进行序列化与反序列化的话,速度远超系统默认的序列化。