垃圾收集 – 为什么c3在此示例中不符合收集条件(SCJP 6)

摘自SCJP 6准备书 –

鉴于:

class CardBoard { Short story = 200; CardBoard go(CardBoard cb) { cb = null; return cb; } public static void main(String[] args) { CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); CardBoard c3 = c1.go(c2); c1 = null; // do Stuff } } 

当达到// doStuff时,有多少对象符合GC条件?

A. 0

B. 1

C. 2

D.编译失败

E.无法知道

F.运行时抛出exception

正确答案是C – “只有一个CardBoard对象(c1)符合条件,但它有一个相关的Short包装器对象,也符合条件。”

我的问题是为什么c3不符合collections资格?

我的想法是 –

c1.go(c2)将本地引用变量cb(它是c2的副本)设置为null,然后返回分配给c3的cb。 我知道c2本身的引用变量不能在方法中修改,只能修改它背后的对象。 但是在我看来,引用变量cb的副本被设置为null并分配给c3。 为什么在此实例中c3未设置为返回的null?

没有与c3相关的对象。 它的值为null,因此无需收集任何内容。

SCJP“正确”的回答是假的。 正确答案是4或“不可能知道”。

如果按字面读取代码(“// do Stuff”只是一个注释),那么先前从c2可以访问的对象就像死了一样,GC符合之前从c1引用的那个,并且因为这两个现在都无法访问对象有一个c1.story和c2.story对象,它们也会死掉它们,总共有4个对象可以收集。

但是,如果“// do Stuff”的东西是某个未知代码的占位符,那么该代码可能会也可能不会使用c2,这意味着c2引用的对象可能已经死亡,也可能没有死亡,并且有资格收集已到达代码。 因此,如果我们不知道“// do Stuff”实际上是什么,那么它是2或4是合格的,并且没有办法分辨哪个。