ObjectInputStream

    ObjectInputStream
    public class ObjectInputStreamextends InputStreamimplements ObjectInput, ObjectStreamConstants
    ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
    ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久性存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
    ObjectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中的显示的类相匹配。使用标准机制按需加载类。
    只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。
    readObject 方法用于从流读取对象。应该使用 Java 的安全强制转换来获取所需的类型。在 Java 中,字符串和数组都是对象,所以在序列化期间将其视为对象。读取时,需要将其强制转换为期望的类型。
    可以使用 DataInput 上的适当方法从流读取基本数据类型。
    默认情况下,对象的反序列化机制会将每个字段的内容还原为写入时它所具有的值和类型。反序列化进程将忽略声明为瞬态或静态的字段。到其他对象的引用使得根据需要从流中读取这些对象。使用引用共享机制能够正确地还原对象的图形。反序列化时始终分配新对象,这样可以避免现有对象被重写。
    读取对象类似于运行新对象的构造方法。为对象分配内存并将其初始化为零 (NULL)。为不可序列化类调用无参数构造方法,然后从以最接近 java.lang.object 的可序列化类开始和以对象的最特定类结束的流还原可序列化类的字段。
    例如,要按 ObjectOutputStream 中示例的写入从流读取,请执行以下操作:
    FileInputStream fis = new FileInputStream(“t.tmp”);
    ObjectInputStream ois = new ObjectInputStream(fis);
    int i = ois.readInt();
    String today = (String) ois.readObject();
    Date date = (Date) ois.readObject();
    ois.close();
    类控制实现 java.io.Serializable 或 java.io.Externalizable 接口时的序列化方式。
    实现 Serializable 接口允许对象序列化,以保存和还原对象的全部状态,并且允许类在写入流时的状态和从流读取时的状态之间变化。它自动遍历对象之间的引用,保存和还原全部图形。
    在序列化和反序列化进程中需要特殊处理的 Serializable 类应该实现以下方法:
    private void writeObject(java.io.ObjectOutputStream stream)
    throws IOException;
    private void readObject(java.io.ObjectInputStream stream)
    throws IOException, ClassNotFoundException;
    private void readObjectNoData()
    throws ObjectStreamException;
    readObject 方法负责使用通过对应的 writeObject 方法写入流的数据,为特定类读取和还原对象的状态。该方法本身的状态,不管是属于其超类还是属于其子类,都没有关系。还原状态的方法是,从个别字段的 ObjectInputStream 读取数据并将其分配给对象的适当字段。DataInput 支持读取基本数据类型。
    尝试读取由对应的 writeObject 方法写入的超出自定义数据边界的对象数据将导致抛出 OptionalDataException(eof 字段值为 true)。超出已分配数据末尾的非对象读取以指示流末尾的方式反映数据末尾:按位读取与字节读取或字节数读取一样,将返回 -1,基元读取将抛出 EOFException。如果不存在对应的 writeObject 方法,则默认的序列化数据的末尾标记已分配数据的末尾。
    从 readExternal 方法发出的基元和对象读取调用的行为方式一样:如果流已经定位在由相应 writeExternal 方法写入的数据末尾,则对象读取将抛出 OptionalDataException(其 eof 设置为 true),按位读取将返回 -1,基元读取将抛出 EOFException。注意,此行为不适用于使用旧 ObjectStreamConstants.PROTOCOL_VERSION_1 协议写入的流,在这些流中,没有划分出由 writeExternal 方法写入的数据末尾,因此无法检测。
    如果序列化流没有将给定类列为要反序列化的对象的超类,则 readObjectNoData 方法负责初始化其特定类的对象状态。在接收方使用的反序列化实例类的版本不同于发送方,并且接收者版本扩展的类不是发送者版本扩展的类时,此事可能发生。如果序列化流已经被篡改,也会发生这种情况;因此,不管源流是“敌意的”还是不完整的,readObjectNoData 方法都可以用来正确地初始化反序列化的对象。
    对于没有实现 java.io.Serializable 接口的任何对象,序列化不会对其字段进行读取或赋值。非 serializable 的 Object 的子类可以为 serializable。在此情况下,非 serializable 类必须具有无参数的构造方法以允许其字段能被初始化。在此情况下,子类负责保存和还原非 serializable 类的状态。经常出现的情况是,该类的字段是可访问的(public、package 或 protected),或者存在可用于还原状态的 get 和 set 方法。
    反序列化对象进程中发生的所有异常将由 ObjectInputStream 捕获并将中止读取进程。
    实现 Externalizable 接口允许对象假定可以完全控制对象的序列化形式的内容和格式。调用 Externalizable 接口的方法(writeExternal 和 readExternal)来保存和恢复对象状态。当这两种方法被某个类实现时,它们可以使用 ObjectOutput 和 ObjectInput 的所有方法读写其本身的状态。对象负责处理出现的任何版本控制。
    Enum 常量的反序列化不同于普通的 serializable 或 externalizable 对象。Enum 常量的序列化形式只包含其名称;不传送常量的字段值。要反序列化 enum 常量,ObjectInputStream 需要从流中读取常量的名称;然后将 enum 常量的基本类型和接收到的常量名称作为参数,调用静态方法 Enum.valueOf(Class, String) 获取反序列化的常量。与其他 serializable 或 externalizable 对象一样,enum 常量可以作为序列化流中随后出现的反向引用的目标。不可以自定义 enum 常量的反序列化进程:在反序列化期间,enum 类型所定义的任何与类有关的 readObject、readObjectNoData 和 readResolve 方法都将被忽略。类似地,任何 serialPersistentFields 或 serialVersionUID 字段声明也将被忽略(所有 enum 类型都有一个固定的 0L 的 serialVersionUID)。

发表评论