Java 序列化是否保留对象标识?
我正在使用JavaJava 序列化是否保留对象标识?,java,serialization,identity,Java,Serialization,Identity,我正在使用JavaSerializable接口和ObjectOutputStream来序列化对象(到目前为止,这种方法对于我来说已经足够了) 我的API在某些操作中依赖于对象标识,我想知道是否可以通过序列化来保留它。也就是说:如果对于两个任意对象a和b,它在序列化之前保持a==b,那么在反序列化之后它仍然保持吗? 我发现了一些文本,但它们要么是关于JRE的旧版本(我只对1.6和1.5感兴趣),要么是关于RMI(这与我无关) 关于对象标识,这个问题还不是很明确。sun.com上的一篇文章提到,Ob
Serializable
接口和ObjectOutputStream
来序列化对象(到目前为止,这种方法对于我来说已经足够了)
我的API在某些操作中依赖于对象标识,我想知道是否可以通过序列化来保留它。也就是说:如果对于两个任意对象a
和b
,它在序列化之前保持a==b
,那么在反序列化之后它仍然保持吗?
我发现了一些文本,但它们要么是关于JRE的旧版本(我只对1.6和1.5感兴趣),要么是关于RMI(这与我无关)
关于对象标识,这个问题还不是很明确。sun.com上的一篇文章提到,ObjectOutputStream
在对象上使用缓存,这对我来说只有在对象标识确实被保留的情况下才有意义,但我没有足够的信心去依赖这一站不住脚的证据
我已经尝试过了(Java1.6,OSX),发现是的,通过序列化,对象的标识保持不变。但我能从这些结果中推断出来吗?还是它们不可靠
在测试中,我序列化了以下对象图:
C----------+
| b1 b2 |
+----------+
| |
v v
B---+ B---+
| a | | a |
+---+ +---+
\ /
\ /
\/
A----+
| |
+----+
最小复制代码:
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);
}
}
答案是否,默认情况下,如果考虑对给定对象/图形进行两次单独的序列化,则不会通过序列化保留对象标识。例如,如果我通过线路序列化一个对象(可能是通过RMI从客户机发送到服务器),然后再次执行(在单独的RMI调用中),那么服务器上的2个反序列化对象将不会为== 然而,在“单一序列化”中,例如,单一客户机-服务器消息是一个多次包含同一对象的图形,然后在反序列化时,标识被保留 但是,对于第一种情况,您可以提供该方法的实现,以确保返回正确的实例(例如,在typesafe枚举模式中)
readResolve
是一个私有方法,JVM将在反序列化Java对象上调用该方法,使该对象有机会返回不同的实例。例如,在将enum
添加到语言之前,TimeUnit
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;
}
}
.对于两个任意对象a和b,如果它在序列化之前保持a==b,则在反序列化之后仍然保持true,如果:
readResolve()
,该类可能会更改恢复引用的方式;持有a和b的课程也不例外对于所有其他情况,对象标识将不会被保留。可能需要将使用ObjectOutputStream类的writeUnshared()方法的结果添加到您的答案中。它最终会在流上创建新的唯一对象。在Java对象序列化规范中有更多信息,谢谢,这正是我一直在寻找的。就我而言,我很幸运。然而,
ObjectInputStream
文档在这里可能更明确。没有定义,“参考文献共享”是一个相当不透明的术语@维内特:谢谢你链接规格。谢谢。使用readResolve
正是我想要避免的,因为在我的例子中,簿记将比使用typesafe枚举模式复杂得多。幸运的是,我只对单个序列化感兴趣。如果它认为a==b,那么它们不是任意对象。我相信你的问题适用于参考资料。