通常我们使用Java的序列化与反序列化时,只需要将类实现Serializable接口即可,剩下的事情就交给了jdk。今天我们就来探究一下,Java序列化是怎么实现的,然后探讨一下几个常见的集合类,他们是如何处理序列化带来的问题的。
Serializable
先看Serializable接口,源码很简单,一个空的接口,没有方法也没有成员变量。但是注释非常详细,很清楚的描述了Serializable怎么用、能做什么,很值得一看,我们捡几个重点的翻译一下,
/**
* Serializability of a class is enabled by the class implementing the
* java.io.Serializable interface. Classes that do not implement this
* interface will not have any of their state serialized or
* deserialized. All subtypes of a serializable class are themselves
* serializable. The serialization interface has no methods or fields
* and serves only to identify the semantics of being serializable.
*/
复制代码
类的可序列化性通过实现java.io.Serializable接口开启。未实现序列化接口的类不能序列化,所有实现了序列化的子类都可以被序列化。Serializable接口没有方法和属性,只是一个识别类可被序列化的标志。
/**
* Classes that require special handling during the serialization and
* deserialization process must implement special methods with these exact
* signatures:
*
* <PRE>
* private void writeObject(java.io.ObjectOutputStream out)
* throws IOException
* private void readObject(java.io.ObjectInputStream in)
* throws IOException, ClassNotFoundException;
* private void readObjectNoData()
* throws ObjectStreamException;
* </PRE>
*/
复制代码
在序列化过程中,如果类想要做一些特殊处理,可以通过实现以下方法writeObject(), readObject(), readObjectNoData(),其中,
- writeObject方法负责为其特定类写入对象的状态,以便相应的readObject()方法可以还原它。
- readObject()方法负责从流中读取并恢复类字段。
- 如果某个超类不支持序列化,但又不希望使用默认值怎么办?writeReplace() 方法可以使对象被写入流之前,用一个对象来替换自己。
- readResolve()通常在单例模式中使用,对象从流中被读出时,可以用一个对象替换另一个对象。
Serializable接口特点
- 序列化类的属性没有实现 Serializable 那么在序列化就会报错
public class User {
private String name;
private int age;
public static void main(String[] args) throws IOException {
try (ObjectOutputStream outputStream =
new ObjectOutputStream(new FileOutputStream("User.txt"))) {
User user = new User();
user.name = "zouwei";
user.age = 22;
outputStream.writeObject(user);
outputStream.flush();
}
}
}
复制代码
编辑切换为居中
添加图片注释,不超过 140 字(可选)
- 在序列化反序列化过程中,父类没有实现序列化接口,那么父类的属性将不会参与到序列化反序列化的过程中,父类需要提供无参构造函数来重新创建对象
public class Animal {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Dog extends Animal implements Serializable {
private static final long serialVersionUID = -8559877565455401808L;
private String name;
public static void main(String[] args) throws Exception {
// 序列化
serialObject();
// 反序列化
deserialObject();
}
private static void serialObject() throws IOException {
try (ObjectOutputStream outputStream =
new ObjectOutputStream(new FileOutputStream("Dog.txt"))) {
Dog dog = new Dog();
dog.name = "Black";
dog