序列化
# 简介
序列化是指把一个Java对象转变为二进制内容,这种操作能够很方便地将某些Java对象远程传输到远端进行使用。序列化后的内容会转变为byte[]
进行保存,远端可以通过反序列化将byte[]
重新转变为Java对象。
一个Java对象要能序列化,必须实现一个特殊的java.io.Serializable
接口,它的定义如下:
public interface Serializable {
}
1
2
2
Serializable
接口没有定义任何方法,它是一个空接口。我们把这样的空接口称为“标记接口”(Marker Interface),实现了标记接口的类仅仅是给自身贴了个“标记”,并没有增加任何方法。
public class Main {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
// 写入int:
output.writeInt(12345);
// 写入String:
output.writeUTF("Hello");
// 写入Object:
output.writeObject(Double.valueOf(123.456));
}
System.out.println(Arrays.toString(buffer.toByteArray()));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
ObjectOutputStream
既可以写入基本类型,如int
,boolean
,也可以写入String
(以UTF-8编码),还可以写入实现了Serializable
接口的Object
。
因为写入Object
时需要大量的类型信息,所以写入的内容很大。
# 反序列化
和ObjectOutputStream
相反,ObjectInputStream
负责从一个字节流读取Java对象:
try (ObjectInputStream input = new ObjectInputStream(...)) {
int n = input.readInt();
String s = input.readUTF();
Double d = (Double) input.readObject();
}
1
2
3
4
5
2
3
4
5
除了能读取基本类型和String
类型外,调用readObject()
可以直接返回一个Object
对象。要把它变成一个特定类型,必须强制转型。
readObject()
可能抛出的异常有:
ClassNotFoundException
:没有找到对应的Class;InvalidClassException
:Class不匹配。
ClassNotFoundException
通常是因为远端没有对象类,因此导致无法成功反序列化
InvalidClassException
则是因为对象类的变量类型与远端所定义的不同,例如A定义了Person
的age
变量类型为int
,但远端定义的是long