序列化是否保留对象标识?

Kon*_*lph 22 java serialization identity

我正在使用Java Serializable接口和ObjectOutputStream序列化对象(到目前为止,这个方法已经足够我的目的).

我的API依赖于某些操作的对象标识,我想知道它是否会被序列化保留.也就是说:如果,对于两个任意对象,a并且ba == b在序列化之前保持,它是否在反序列化后仍然保持?

我发现了一些声称相反的文本- 但他们要么写了一个旧版本的JRE(我只对1.6和1.5感兴趣),要么关注RMI(这与我无关).

有关对象标识的文档不是很明确.一个技术性文章对sun.com提到了ObjectOutputStream使用上的对象缓存,这对我来说才有意义,如果该对象的身份确实保留,但我没有足够的信心,靠这个脆弱的证据.

我已经尝试过(Java 1.6,OS X),发现是的,对象的身份通过序列化保持不变.但我可以从这些结果中推断出来还是不可靠?

对于我的测试,我已经序列化了以下对象图:

C----------+
| b1    b2 |
+----------+
  |      |
  v      v
B---+  B---+
| a |  | a |
+---+  +---+
   \    /
    \  /
     \/
   A----+
   |    |
   +----+
Run Code Online (Sandbox Code Playgroud)

最小的再现代码:

import java.io.*;

public class SerializeTest {
    static class A implements Serializable {}

    static class B implements Serializable {
        final A a;

        public B(A a) {
            this.a = a;
        }
    }

    static class C implements Serializable {
        final B b1, b2;

        public C() {
            A object = new A();
            b1 = b2 = new B(object);
        }
    }

    public static void main(String[] args) throws IOException,
            ClassNotFoundException {
        C before = new C();
        System.out.print("Before: ");
        System.out.println(before.b1.a == before.b2.a);

        // Serialization.
        ByteArrayOutputStream data = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(data);
        out.writeObject(before);
        out.close();

        // Deserialization.
        ObjectInputStream in =
            new ObjectInputStream(new ByteArrayInputStream(data.toByteArray()));
        C after = (C) in.readObject();
        System.out.print("After: ");
        System.out.println(after.b1.a == after.b2.a);
    }
}
Run Code Online (Sandbox Code Playgroud)

Chs*_*y76 18

对于两个任意对象a和b,如果它在序列化之前保持== b,则在反序列化IF后它仍将保持为真:

  1. a和b都被写入并随后作为相同流的一部分读取.以下是ObjectInputStream文档的引用:"使用引用共享机制正确恢复对象图."
  2. a和b的类不会覆盖readResolve(),有可能改变引用的恢复方式; 持有a和b的班级也没有.

对于所有其他情况,将不保留对象标识.

  • 可能希望将使用ObjectOutputStream类的writeUnshared()方法的后果添加到您的答案中.它最终在流上创建新的唯一对象.有关Java对象序列化规范的更多信息,请访问http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf (2认同)

oxb*_*kes 10

答案是否定的,默认情况下,如果您正在考虑给定对象/图形的2个单独序列化,则不会通过序列化保留对象标识.例如,如果一个序列化对象通过线路(也许我把它从客户端通过RMI服务器),然后再做一遍(在单独的RMI调用),然后在服务器上的2个反序列化对象将被==.

然而,在"单序列",例如为含有相同的对象的多个次,然后在反序列化的曲线图的单个客户端-服务器消息,身份保留.

但是,对于第一种情况,您可以提供该readResolve方法的实现,以确保返回正确的实例(例如,在类型安全的枚举模式中).readResolve是一个私有方法,它将由JVM在反序列化的Java对象上调用,使对象有机会返回不同的实例.例如,这是在将语言添加到语言TimeUnit enum之前实现enum的方式:

public class TimeUnit extends Serializable {

    private int id;
    public TimeUnit(int i) { id = i; }
    public static TimeUnit SECONDS = new TimeUnit(0);

    //Implement method and return the relevant static Instance
    private Object readResolve() throws ObjectStreamException {
        if (id == 0) return SECONDS;
        else return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

.