为什么要进行序列化呢?
主要是为了把一个对象(结构化的数据)转化成一个 字符串 / 字节数组,方便我们存储(有时候需要将数据存储到文件中,而文件只能存 字符串 / 二进制数据,不方便直接存储 对象)和传输数据(通过网络传输).
如何实现 对象与二进制数据 的序列化和反序列化?
实际上针对二进制序列化也是有很多种方案的:
1. Java 标准库提供了序列化的方案,ObjectInputStream 和 ObjectOutputStream(推荐).
2. Hessian.
3. protobuffer
4. thrift.
5. 通过一些转化也可以使用 JSON 表示二进制数据(JSON 格式中有很多特殊符号:" {} 这些符号会影响 JSON 格式的解析):可以针对 二进制数据 进行 base64 编码. base64 的作用就是用 4 字节表示 3 个字节信息,会保证 4 个字节都是使用 文本字符(相当于是把 二进制数据转换成文本了, 就像是 HTML 中嵌入一个图片,就可以把图片的二进制 base64 编码 直接以文本的形式嵌入到 html 中),但是 base64 这种方案,效率低,有额外的转码开销,同时还会使空间变大.
Ps:这里我们使用方案一,也就是标准库自带的方案,这个方案最大的好处就是不必引入额外的依赖.
具体实现如下:
- 首先,如果想要这个对象能够序列化或者反序列化,就需要这个类能实现 Serializable 接口(无需重写任何方法)
- ByteArrayOutputStream:把 对象 序列化成 字节数组,流对象就相当于是一个变长的字节数组,通过 object 序列化数据,然后逐渐写入到 ByteArrayOutputStream 中,再统一转化成 byte[] 即可.
- ByteArrayInputStream:把 字节数组 反序列化成 对象,将需要转化的二进制数据交给 byteArrayInputStream,再把 byteArrayInputStream 交给 ObjectInputStream ,然后通过 readObject 方法就可以反序列化成对象了.
public class BinaryTool {
/**
* 把一个对象序列化成一个字节数组
* @param object
* @return
*/
public static byte[] toBytes(Object object) throws IOException {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
//此处 writeObject 就会把该对象进行序列化,生成的二进制字节数据,写入到 ObjectOutputStream 中
//又由于 ObjectOutputStream 又关联到了 ByteArrayOutputStream,最终就写入到了 ByteArrayOutputStream
objectOutputStream.writeObject(object);
}
return byteArrayOutputStream.toByteArray();
}
}
/**
* 把一个字节数组反序列化成对象
* @param data
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static Object fromBytes(byte[] data) throws IOException, ClassNotFoundException {
Object object = null;
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) {
try (ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
//此处的 readObject 就是从 data 这个 byte 中读取数据并进行反序列化
object = objectInputStream.readObject();
}
}
return object;
}
}
Ps:不要混淆输入和输出的概念
inputstream 和 outputstream 都是对流的定义,这两个操作的中心都是内存,所以要理解他们的区别,关键就是理解内存和其他容器的交换。
内存-------------》屏幕 outputstream
屏幕-------------》内存 inputstream内存-------------》硬盘 outoutstream 之后进行写操作write 将内容写入硬盘文件中
硬盘-------------》内存 inputstream 之后进行读操作read 将内容从硬盘读出到内存中进行,然后对其进行操作。