对象的输入输出-Java序列化机制

对象序列化和反序列化,在Java中体现为两种字节流: ObjectInputStreamObjectOutputStream

序列化的概念

指堆内存中的java对象数据,通过某种方式存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转化成二进制的过程。

反序列化,顾名思义,则是将二进制字节流转化回java对象的过程。

java序列化是平台无关的

序列化的作用

  1. 对象持久化
  2. 网络传输对象
  3. 进程间传递对象

如何序列化

默认序列化

  1. 为类实现一个Serializable接口,这是一个空接口,没有需要实现的方法。
  2. 可以调用ObjectOutputStream.writeObject方法来序列化了。
  3. 调用ObjectInputStream.readObject来反序列化

自定义序列化过程

实现Serializable接口之后,重写 writeObject(ObjectOutputStream) 、 readObject(ObjectInputStream) 方法。

序列化ID

通常可序列化的类会使用一个序列化ID:

private static final long serialVersionUID = 1L;

java的序列化机制是通过判断运行时类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常InvalidClassException

序列化之后的字节流格式

我们用这样一段代码做实验:

class SerializableObject implements Serializable{ }

public class Main {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(System.out);
        Object obj = new SerializableObject();
        out.writeObject(obj);
    }
}

得到的结果为:

aced 0005 7372 0012 5365 7269 616c 697a
6162 6c65 4f62 6a65 6374 0b8e b091 7d68
738d 0200 0078 70

前两个字节固定: ac ed

紧接的是对象序列化格式的版本号: 00 05

接下来,73 代表接下来读取到的将是一个对象,72 代表该对象是一个对类的描述:73 72

接下来的两字节描述类名长度:00 12,对应18个字节的全限定类名。

于是接下来的18字节就是类名的UTF编码:5365 7269 616c 697a 6162 6c65 4f62 6a65 6374,就是类名SerializableObject。

接下来八个字节是序列化版本ID:0b8e b091 7d68 738d

接下来一个字节02代表了序列化中标识类版本。

继续往下两个字节就是 00 00 , 代表该类中字段的个数,由于我这个类内部为空没有字段,所以这里就是0。

然后是它包含的字段序列类型描述,其顺序即它们存储的顺序.

基本类型的组成为:一字节类型描述符 两字节字段名称长度 字段名称

类型描述符:

解码字符 代表类型
B byte
C char
D double
F float
I int
J long
L 对象
S short
Z boolean
[ 数组

字段序列类型描述结束后附加两个字节是固定的78 70

最后是字段信息(内容)的描述,这里都没有。

特殊情况

  1. 静态变量不会被序列化(static),transient则可以限定字段不参与序列化。
  2. 当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。
  3. 当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e5%af%b9%e8%b1%a1%e7%9a%84%e8%be%93%e5%85%a5%e8%be%93%e5%87%ba-java%e5%ba%8f%e5%88%97%e5%8c%96%e6%9c%ba%e5%88%b6/

发表评论

电子邮件地址不会被公开。