序列化
Java 的序列化就是将一个 Java 对象转化为一个字节流的一种机制。从字节流再转回 Java 对象叫做反序列化,是序列化的反向操作。
序列化和反序列化是和平台无关的,也就是说你可以在 Linux 系统序列化,然后在 Windows 操作系统做反序列化。
如果要序列化对象,需要使用 ObjectOutputStream 类的 writeObject() 方法。如果要做反序列化,则要使用 ObjectOutputStream 类的 readObject() 方法。
如下图所示,对象被转化为字节流后,被储存在了不同的介质中。这个流程就是序列化。在图的右边,也可以看到从不同的介质中,比如内存,获得字节流并转化为对象,这叫做反序列化。
为什么使用序列化
如果我们创建了一个 Java 对象,这个对象的状态在程序执行完毕或者退出后就消失了,不会得到保存。
所以,为了能解决这类问题,Java 提供了序列化机制。这样,我们就能把对象的状态做临时储存或者进行持久化,以供后续当我们需要这个对象时,可以通过反序列化把对象还原回来。
下面给出一些代码看看我们是怎么来做序列化的。
import java.io.Serializable;
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
private String serializeValueName;
private transient String nonSerializeValuePos;
public String getSerializeValueName() {
return serializeValueName;
}
public void setSerializeValueName(String serializeValueName) {
this.serializeValueName = serializeValueName;
}
public String getNonSerializeValueSalary() {
return nonSerializeValuePos;
}
public void setNonSerializeValuePos(String nonSerializeValuePos) {
this.nonSerializeValuePos = nonSerializeValuePos;
}
@Override
public String toString() {
return "Player [serializeValueName=" + serializeValueName + "]";
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializingObject {
public static void main(String[] args) {
Player playerOutput = null;
FileOutputStream fos = null;
ObjectOutputStream oos = null;
playerOutput = new Player();
playerOutput.setSerializeValueName("niubi");
playerOutput.setNonSerializeValuePos("x:1000,y:1000");
try {
fos = new FileOutputStream("Player.ser");
oos = new ObjectOutputStream(fos);
oos.writeObject(playerOutput);
System.out.println("序列化数据被存放至Player.ser文件");
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output:序列化数据被存放至Player.ser文件
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeSerializingObject {
public static void main(String[] args) {
Player playerInput = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("Player.ser");
ois = new ObjectInputStream(fis);
playerInput = (Player) ois.readObject();
System.out.println("从Player.ser文件中恢复");
ois.close();
fis.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("player名字为 : " + playerInput.getSerializeValueName());
System.out.println("player位置为 : " + playerInput.getNonSerializeValuePos());
}
}
Output:
从Player.ser文件中恢复
player名字为 : niubi
player位置为 : null
关键特性
- 如果父类实现了 Serializable 接口那么子类就不必再实现 Serializable 接口了。但是反过来不行。
- 序列化只支持非 static 的成员变量
- static 修饰的变量和常量以及被 transient 修饰的变量是不会被序列化的。所以,如果我们不想要序列化某些非 static 的成员变量,直接用 transient 修饰它们就好了。
- 当反序列化对象的时候,是不会调用对象的构造函数的。
- 如果一个对象被一个要序列化的对象引用了,这个对象也会被序列化,并且这个对象也必须要实现 Serializable 接口。