3

取自 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. 运行时抛出异常

正确答案是 C -“只有一个 CardBoard 对象 (c1) 符合条件,但它有一个关联的 Short wrapper 对象也符合条件。”

我的问题是为什么 c3 没有资格收集?

我的想法是——

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

4

2 回答 2

7

没有与 c3 相关的对象。它的值为空,所以没有什么可收集的。

于 2013-09-18T14:47:38.730 回答
1

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

如果按字面意思阅读代码(“// do Stuff”只是一个注释),那么之前从 c2 可访问的对象与之前从 c1 引用的对象一样已死且符合 GC 条件,并且由于这两个对象现在都无法访问对象有一个 c1.story 和 c2.story 对象,它们也会随之死亡,共有 4 个对象符合收集条件。

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

于 2013-09-21T07:59:47.180 回答