避免Java反序列化中的重复对象

时间:2010-04-19 06:38:00

标签: java serialization

我有两个列表(list1和list2),其中包含对某些对象的引用,其中一些列表条目可能指向同一个对象。然后,由于各种原因,我将这些列表序列化为两个单独的文件。最后,当我反序列化列表时,我想确保我不会重新创建超出需要的对象。换句话说,List1的某些条目仍然可以指向与List2中的某个条目相同的对象。

MyObject obj = new MyObject();
List<MyObject> list1 = new ArrayList<MyObject>();
List<MyObject> list2 = new ArrayList<MyObject>();
list1.add(obj);
list2.add(obj);

// serialize to file1.ser
ObjectOutputStream oos = new ObjectOutputStream(...);
oos.writeObject(list1);
oos.close();

// serialize to file2.ser
oos = new ObjectOutputStream(...);
oos.writeObject(list2);
oos.close();

我认为spec的3.4和A.2节说反序列化严格导致新对象的创建,但我不确定。如果是这样,一些可能的解决方案可能涉及:

  1. 实现equals()和hashCode()并手动检查引用。
  2. 创建一个“容器类”来保存所有内容,然后序列化容器类。
  3. 是否有一种简单的方法可以确保在反序列化时不会重复对象?

    感谢。

3 个答案:

答案 0 :(得分:4)

在对第二个列表进行反序列化后,您可以迭代它的元素,并通过对第一个列表的引用来替换重复项。

根据3.7 The readResolve Method,在对象完全构造之前,不会在对象上调用readResolve()方法。

答案 1 :(得分:3)

  

我认为规范的3.4和A.2节说反序列化严格地导致了新对象的创建,但是我不确定。如果是这样,一些可能的解决方案可能涉及:...

     
    

2,创建一个“容器类”来保存所有内容,然后序列化容器类。

  

我将这些语句读作“如果我对反序列化总是创建新对象的理解不正确,那么将包含在容器类中的两个列表写入单个流的解决方案#2是可接受的解决方案。” EM>

如果我理解正确,这意味着您认为通过包含两个列表的单个容器写出将无法工作,因为它仍然会导致重复的对象(“严格导致...新对象”)。这是不正确的。在写出对象图(包装类)时,无论图中出现多少次,每个对象都只被序列化一次。读回图形时,该对象不会重复。

http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html

  

对象的默认序列化机制会写入对象的类,类签名以及所有非瞬态和非静态字段的值。对其他对象的引用(瞬态或静态字段除外)也会导致写入这些对象。 使用参考共享机制对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。

所以,如果可以,请使用选项#2。

  

创建一个“容器类”来保存所有内容,然后序列化容器类。

答案 2 :(得分:2)

您可以覆盖readResolve()方法,用您想要的任何内容替换从流中读取的内容。

private Object readResolve() throws ObjectStreamException {
  ...
}

这通常用于强制执行单身人士。在Java 5之前,它还用于类型安全枚举。我从来没有见过它用于此但情况,但我想没有理由它不可能。

现在,这将适用于您控制的单个对象,但我无法看到您是如何使用List创建的。它可以确保列表中返回的对象不会重复(按照您认为的任何标准)。