【问题标题】:When would one use ObjectInputStream.readUnshared() vs .readObject()?什么时候会使用 ObjectInputStream.readUnshared() 和 .readObject()?
【发布时间】:2015-06-08 01:59:52
【问题描述】:

Java ObjectInputStream 中有两个类似的方法:

readUnshared()

readObject()

文档说明:

public Object readUnshared() throws IOException, ClassNotFoundException

从 ObjectInputStream 中读取一个“非共享”对象。此方法与 readObject 相同,只是它阻止对 readObject 和 readUnshared 的后续调用返回对通过此调用获得的反序列化实例的附加引用。具体来说:

如果调用 readUnshared 来反序列化反向引用(之前已写入流的对象的流表示),则会抛出 ObjectStreamException。

如果 readUnshared 成功返回,则任何后续尝试反序列化对由 readUnshared 反序列化的流句柄的反向引用将导致抛出 ObjectStreamException。

通过 readUnshared 反序列化对象会使与返回对象关联的流句柄无效。请注意,这本身并不总是保证 readUnshared 返回的引用是唯一的;反序列化的对象可以定义一个 readResolve 方法,该方法返回一个对其他方可见的对象,或者 readUnshared 可以返回一个 Class 对象或枚举常量,可在流中的其他地方或通过外部方式获得。如果反序列化的对象定义了一个 readResolve 方法并且该方法的调用返回一个数组,那么 readUnshared 返回该数组的一个浅表克隆;这保证了返回的数组对象是唯一的,并且不能从 ObjectInputStream 上的 readObject 或 readUnshared 调用第二次获得,即使底层数据流已被操作。

覆盖此方法的ObjectInputStream 子类只能在拥有“enableSubclassImplementation”SerializablePermission 的安全上下文中构建;任何在没有此权限的情况下实例化此类子类的尝试都将导致抛出 SecurityException。

但我想知道是否有人使用.readUnshared().readObject() 对此有实际用途

【问题讨论】:

  • 没用过。一种用途是作为协议健全性检查,以确保发件人使用writeUnshared(). 如果他不是所描述的异常,则会导致。

标签: java oracle java-7 objectinputstream objectoutputstream


【解决方案1】:

我相信这可能是与安全相关的非常特殊的情况(?)。喜欢这个(来自here)。

A.6 保护未共享的反序列化对象

如果一个类有任何私有或包私有对象引用字段, 并且类取决于这些对象引用不是 在类(或包)之外可用,然后是引用的 作为反序列化的一部分,必须防御性地复制对象 进程,否则 ObjectOutputStream.writeUnshared 和 ObjectInputStream.readUnshared 方法(在 1.4 版本中引入 JavaTM 2 SDK,标准版)应用于确保唯一 对内部对象的引用。

在复制方法中,从流中反序列化的子对象 应被视为“不受信任的输入”:新创建的对象, 初始化为与反序列化的子对象具有相同的值, 应该用 readObject 方法替换子对象。 例如,假设一个对象有一个私有字节数组字段 b,它 必须保持私密:

 private void readObject(ObjectInputStream s)
    throws IOException, ClassNotFoundException
{
    s.defaultReadObject();

    b = (byte[])b.clone();

    if (<invariants are not satisfied>)
        throw new java.io.StreamCorruptedException();
}

这个问题在考虑序列化时尤为重要 包含内部(必须是私有的)引用的不可变对象 可变子对象。如果不采取特殊措施复制子对象 在容器对象的反序列化过程中,恶意方 对序列化流的写访问可能会违反容器对象的 通过伪造对其可变子对象的引用并使用这些 引用来改变容器对象的内部状态。因此,在这个 在这种情况下,不可变容器类必须提供一个 特定于类的反序列化方法,它制作私有副本 它反序列化的每个可变组件对象。请注意,对于 保持不变性的目的,没有必要复制 不可变的组件对象。

还需要注意的是,调用 clone 可能并不总是 防御性复制子对象的正确方法。如果克隆方法不能 被指望制作一个独立的副本(而不是“偷”一个 参考副本),应使用另一种方法来制作 副本。应始终使用其他复制方式,如果 子对象的类不是最终的,因为克隆方法或助手 它调用的方法可能会被子类覆盖。

从 JavaTM 2 SDK 标准版 1.4 版开始,唯一 对反序列化对象的引用也可以通过使用 ObjectOutputStream.writeUnshared 和 ObjectInputStream.readUnshared 方法,从而避免了复杂性、性能成本和内存 防御性复制的开销。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    相关资源
    最近更新 更多