在存在序列化的情况下理解Java内存模型下的棘手案例

时间:2015-08-06 14:30:15

标签: java memory serialization garbage-collection

您好我无法理解以下代码在序列化下的行为方式。

Foo被创建为临时对象,最终被用在Bar的匿名后代的方法中。 Bar是一个字段,并且在创建Foo对象的方法中幸存。

如何存储Foo对象。它是一个隐含的领域"酒吧对象?它是一个隐含的领域"程序对象?只是在Bar :: doSomething实现的代码中引用时,它是否仅在Heap上浮动?

我假设垃圾收集器足够智能,不会删除此对象。但序列化和反序列化后的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();
  }
}

2 个答案:

答案 0 :(得分:1)

这里你实际上有两个问题。第一个是您正在创建的Bar类的实例是Program的内部类,而Program不是可序列化的。如果您尝试序列化匿名内部类,即使不担心Foo,也会出现错误。

当您创建匿名内部类时,类的代码中引用的任何变量都将通过Java透明生成的构造函数复制到类中。这些变量成为该类的实例字段,因此必须可序列化才能序列化该类。

答案 1 :(得分:0)

如果Foo不是可序列化,则无效。你会得到java.io.NotSerializableException

如果Foo是可序列化的,那么它将与Bar一起序列化并成功反序列化。

  

如何存储Foo对象?它是一个隐含的领域"吧对象?

不确定如何,我认为无所谓。重要的是它被存储(iff Foo是可序列化的;否则你得到一个例外,如上所述)。

  

只是在Bar :: doSomething实现的代码中引用时,它是否仅在Heap上浮动?

它不会浮动,它会在堆上放置。只要存在对此对象的实时引用,垃圾收集器就不会接收它。由于foo.doSomethingElse()引用堆上的真实foo对象,它将保留在那里(实际上,这是创建内存泄漏的方法之一)。

  

但是,序列化和反序列化后的Bar对象是否仍然指向同一个对象?

没有。将创建类型为Bar的新对象,从而还原序列化对象的状态。