20201016邹瑞

总结

序列化

概念

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该 对象的数 据 、 对象的类型和 对象中存储的属性 等信息。字节序列写出到文件之后,相当于文件中持久保存了一 个对象的信息。 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、 对象的类 型 和 对象中存储的数据 信息,都可以用来在内存中创建对象。 简单说序列化是指把一个Java对象变成二进制内容,本质上就是一个 byte[] 数组。
为什么要把Java对象序列化呢?
因为序列化后可以把 byte[] 保存到文件中,或者把 byte[] 通过网络传输到远程,这样,就相当于把 Java对象存储到文件或者通过网络传输出去了。有序列化,就有反序列化,即把一个二进制内容(也就 是 byte[] 数组)变回Java对象。有了反序列化,保存到文件中的 byte[] 数组又可以“变回”Java对象, 或者从网络上读取 byte[] 并把它“变回”Java对象。

Serializable

public interface Serializable { }

序列化需要类实现 java.io.Serializable 接口,也就是说不实现此接口的类将不能序列化或反序列 化。 Serializable 类的所有子类都是可序列化的。序列化接口没有方法或字段,仅用于标识可 串行化 的语义。我们把这样的空接口称为“标记接口”(Marker Interface)实现了标记接口的类仅仅是给自身 贴了个“标记”,并没有增加任何方法

ObjectOutputStream

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到流,实现对象的持久存储。

public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants

序列化操作

序列化为byte[]

ObjectOutputStream 既可以写入基本类型,如 int , boolean ,也可以写入 String (以UTF-8编 码),还可以写入实现了 Serializable 接口的 Object 。
因为写入 Object 时需要大量的类型信息,所以写入的内容很大

对象序列化

创建一个 Student 类,并实现 Serializable 接口

ObjectInputStream

和 java.io.ObjectOutputStream 相反, java.io.ObjectInputStream 负责从一个字节流读取Java 对象。将之前使用 ObjectOutputStream 序列化的原始数据恢复为对象.

public class ObjectInputStream

extends InputStream implements ObjectInput, ObjectStreamConstants

反序列化

如果能找到一个对象的 class 文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对 象的方法。

反序列化过程中,将字节序列转换成了对象,这个对象的创建没有经过构造方法。这个对象中的域(属 性)的值是固定的,如果是 transient 声明的域(属性)值是其类型的默认值。

对于 JVM 可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出 一个 ClassNotFoundException 异常。
另外,当 JVM 反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么 反序列化操作也会失败,抛出一个 InvalidClassException 异常。
为了避免这种 class 定义变动导致的不兼容,Java的序列化允许class定义一个特殊的 serialVersionUID 静态常量,用于标识Java类的序列化“版本”,通常可以由IDE自动生成。如果增加或 修改了字段,可以改变 serialVersionUID 的值,这样就能自动阻止不匹配的class版本:

// 加入序列版本号 private static final long serialVersionUID = 1L;

这个时候序列化完成后,修改类后,可以反序列化。
要特别注意反序列化的几个重要特点:
反序列化时,由JVM直接构造出Java对象,不调用构造方法,构造方法内部的代码,在反序列化时 根本不可能执行

心得

学习使我快乐

标签

评论

this is is footer