何时使用ObjectInputStream.readUshared()vs .readObject()?

时间:2015-04-02 23:59:48

标签: java oracle java-7 objectinputstream objectoutputstream

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() vs .readObject()

进行实际使用

1 个答案:

答案 0 :(得分:0)

我认为这可能是与安全相关的非常特殊的案例(?)。喜欢这个(来自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();
}
     

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

     

同样重要的是要注意,调用克隆可能并不总是如此   正确的方法来防御性地复制子对象。如果克隆方法不能   被指望产生一个独立的副本(而不是&#34;窃取&#34; a   参考副本),应使用替代手段来制作   副本。如果是,应始终使用另一种复制方法   由于克隆方法或帮助器,子对象的类不是最终的   它调用的方法可以被子类覆盖。

     

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