java readunshared_ObjectInputStream

ObjectInputStream对先前使用ObjectOutputStream编写的原始数据和对象进行反序列化。

警告:不受信任数据的反序列化本质上是危险的,应该避免。

当与FileOutputStream和FileInputStream一起使用时,ObjectOutputStream和ObjectInputStream可以为对象图提供持久存储的应用程序。 ObjectInputStream用于恢复以前序列化的对象。 其他用途包括使用套接字流在主机之间传递对象,或者用于在远程通信系统中编组和解组参数和参数。

ObjectInputStream确保从流创建的图中的所有对象的类型与Java虚拟机中存在的类相匹配。 使用标准机制根据需要加载类。

只能从流中读取支持java.io.Serializable或java.io.Externalizable接口的对象。

方法readObject用于从流中读取对象。 应该使用Java的安全转换来获得所需的类型。 在Java中,字符串和数组是对象,在序列化期间被视为对象。 读取时,需要将它们转换为预期的类型。

可以使用DataInput上的适当方法从流中读取原始数据类型。

对象的默认反序列化机制将每个字段的内容还原为值,并在写入时键入。 反序列化过程将忽略声明为transient或static的字段。 对其他对象的引用会导致必要时从流中读取这些对象。 使用参考共享机制正确恢复对象图。 在反序列化时始终会分配新对象,这会阻止覆盖现有对象。

读取对象类似于运行新对象的构造函数。 为对象分配内存并初始化为零(NULL)。 对非序列化类调用no-arg构造函数,然后从最接近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接口允许对象序列化来保存和恢复对象的整个状态,并允许类在写入流的时间和读取时间之间进行演变。 它会自动遍历对象之间的引用,保存和恢复整个图形。

在序列化和反序列化过程中需要特殊处理的可序列化类应实现以下方法:

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方法写入的自定义数据边界的对象数据的尝试都将导致使用eof字段值为true抛出OptionalDataException。 超出分配数据末尾的非对象读取将以它们指示流结束的相同方式反映数据的结束:逐字节读取将返回-1作为字节读取或读取的字节数,以及原语读取将抛出EOFExceptions。 如果没有相应的writeObject方法,则默认序列化数据的结尾标记分配数据的结束。

从readExternal方法中发出的原始和对象读取调用的行为方式相同 - 如果流已经位于相应writeExternal方法写入的数据的末尾,则对象读取将抛出OptionalofExceptions,并将eof设置为true,逐字节读取将返回-1,原始读取将抛出EOFExceptions。 请注意,对于使用旧的ObjectStreamConstants.PROTOCOL_VERSION_1协议编写的流,此行为不适用,其中writeExternal方法写入的数据末尾未划分,因此无法检测到。

readObjectNoData方法负责在序列化流未将给定类列为要反序列化的对象的超类的情况下初始化其特定类的对象的状态。 如果接收方使用与发送方不同版本的反序列化实例的类,并且接收方的版本扩展了未由发送方版本扩展的类,则可能发生这种情况。 如果序列化流已被篡改,也可能发生这种情况; 因此,尽管存在“恶意”或不完整的源流,readObjectNoData对于正确初始化反序列化对象非常有用。

序列化不会读取或为未实现java.io.Serializable接口的任何对象的字段赋值。 不可序列化的对象的子类可以是可序列化的。 在这种情况下,非可序列化类必须具有no-arg构造函数以允许其字段被初始化。 在这种情况下,子类负责保存和恢复非可序列化类的状态。 通常情况下,该类的字段可以访问(公共,包或受保护),或者有get和set方法可用于恢复状态。

在反序列化期间可以过滤流的内容。 如果filter is set上的ObjectInputStream的,所述ObjectInputFilter可以检查类,阵列的长度,在流,深度和数量从输入流消耗的字节的参考数是允许的,如果没有,可以终止反序列化。

反序列化对象时发生的任何异常都将被ObjectInputStream捕获并中止读取过程。

实现Externalizable接口允许对象完全控制对象的序列化表单的内容和格式。 调用Externalizable接口的方法writeExternal和readExternal来保存和恢复对象状态。 当由类实现时,他们可以使用ObjectOutput和ObjectInput的所有方法编写和读取自己的状态。 对象负责处理发生的任何版本控制。

枚举常量的反序列化与普通的可序列化或可外部化的对象不同。 枚举常量的序列化形式仅由其名称组成; 不传输常量的字段值。 要反序列化枚举常量,ObjectInputStream从流中读取常量名称; 然后通过使用枚举常量的基类型和接收的常量名称作为参数调用静态方法Enum.valueOf(Class, String)获得反序列化的常量。 与其他可序列化或可外部化的对象一样,枚举常量可以作为随后出现在序列化流中的反向引用的目标。 无法自定义枚举常量反序列化的过程:在反序列化期间,将忽略由枚举类型定义的任何特定于类的readObject,readObjectNoData和readResolve方法。 同样,任何serialPersistentFields或serialVersionUID字段声明也会被忽略 - 所有枚举类型都有一个固定的serialVersionUID为0L。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值