在存在序列化的情况下理解 Java 内存模型下的一个棘手案例
Understanding a tricky case under the Java memory model in the presence of serialization
您好,我无法理解以下代码在序列化下的行为方式。
Foo 被创建为一个临时对象,并最终在 Bar 的匿名后代的方法中使用。 Bar 是一个字段并且在创建 Foo 对象的方法中存在。
Foo 对象是如何存储的。是bar对象的"implicit field"吗?它是 Program 对象的 "implicit field" 吗?它是否只是在堆上浮动而仅在 Bar::doSomething 实现的代码中被引用?
我假设垃圾收集器足够聪明,不会删除这个对象。但是经过序列化和反序列化后的Bar对象还会指向同一个对象吗? Foo 不可序列化,因此不能自行序列化。
对于那些想知道的人,该示例派生自我正在编写的 Wicket 应用程序,在我的例子中,Foo 和 Bar 是模型。因此 Foo 也是可序列化的,但是当 Foo 不可序列化时这个问题似乎更有趣。
class Foo {
public void doSomethingElse() {
}
}
abstract class Bar implements Serializable {
public abstract void doSomething();
}
class Program {
Bar bar;
void main(String[] args) {
otherMethod(new Foo());
}
void otherMethod(Foo foo) {
bar = new Bar() {
@Override
public void doSomething() {
foo.doSomethingElse();
}
};
}
// much later after bar has been serialized and deserialized
void calledMuchLater() {
bar.doSomething();
}
}
如果 Foo
不是 可序列化的 ,这将不起作用。你会得到一个 java.io.NotSerializableException
.
如果Foo
是可序列化的,那么它将与Bar
一起序列化并反序列化成功。
How is the Foo object stored? Is it a "implicit field" of the bar object?
不确定具体如何,我认为这无关紧要。重要的是它被存储(iff Foo
是可序列化的;否则你会得到我上面所说的异常)。
Does it just float around on the Heap while being referenced only in the code of the Bar::doSomething implementation?
它不会四处漂浮,它在堆上有它的位置。只要存在对该对象的实时引用,垃圾收集器就不会拾取它。由于 foo.doSomethingElse()
引用堆上的真实 foo 对象,它将保留在那里(实际上,这是造成内存泄漏的方法之一)。
But will the Bar object after being serialized and deserialized still point to the same object?
没有。将创建 Bar
类型的新对象,恢复序列化对象的状态。
你实际上会遇到两个问题。首先是您正在创建的 Bar class 实例是 Program 的内部 class,并且 Program 不可序列化。如果你试图序列化匿名内部 class 你会得到一个错误,即使不担心 Foo.
当您创建匿名内部 class 时,class 的代码中引用的任何变量都将通过透明生成的构造函数复制到 class Java。这些变量成为 class 的实例字段,因此必须可序列化才能序列化 class.
您好,我无法理解以下代码在序列化下的行为方式。
Foo 被创建为一个临时对象,并最终在 Bar 的匿名后代的方法中使用。 Bar 是一个字段并且在创建 Foo 对象的方法中存在。
Foo 对象是如何存储的。是bar对象的"implicit field"吗?它是 Program 对象的 "implicit field" 吗?它是否只是在堆上浮动而仅在 Bar::doSomething 实现的代码中被引用?
我假设垃圾收集器足够聪明,不会删除这个对象。但是经过序列化和反序列化后的Bar对象还会指向同一个对象吗? Foo 不可序列化,因此不能自行序列化。
对于那些想知道的人,该示例派生自我正在编写的 Wicket 应用程序,在我的例子中,Foo 和 Bar 是模型。因此 Foo 也是可序列化的,但是当 Foo 不可序列化时这个问题似乎更有趣。
class Foo {
public void doSomethingElse() {
}
}
abstract class Bar implements Serializable {
public abstract void doSomething();
}
class Program {
Bar bar;
void main(String[] args) {
otherMethod(new Foo());
}
void otherMethod(Foo foo) {
bar = new Bar() {
@Override
public void doSomething() {
foo.doSomethingElse();
}
};
}
// much later after bar has been serialized and deserialized
void calledMuchLater() {
bar.doSomething();
}
}
如果 Foo
不是 可序列化的 ,这将不起作用。你会得到一个 java.io.NotSerializableException
.
如果Foo
是可序列化的,那么它将与Bar
一起序列化并反序列化成功。
How is the Foo object stored? Is it a "implicit field" of the bar object?
不确定具体如何,我认为这无关紧要。重要的是它被存储(iff Foo
是可序列化的;否则你会得到我上面所说的异常)。
Does it just float around on the Heap while being referenced only in the code of the Bar::doSomething implementation?
它不会四处漂浮,它在堆上有它的位置。只要存在对该对象的实时引用,垃圾收集器就不会拾取它。由于 foo.doSomethingElse()
引用堆上的真实 foo 对象,它将保留在那里(实际上,这是造成内存泄漏的方法之一)。
But will the Bar object after being serialized and deserialized still point to the same object?
没有。将创建 Bar
类型的新对象,恢复序列化对象的状态。
你实际上会遇到两个问题。首先是您正在创建的 Bar class 实例是 Program 的内部 class,并且 Program 不可序列化。如果你试图序列化匿名内部 class 你会得到一个错误,即使不担心 Foo.
当您创建匿名内部 class 时,class 的代码中引用的任何变量都将通过透明生成的构造函数复制到 class Java。这些变量成为 class 的实例字段,因此必须可序列化才能序列化 class.