Java 符合垃圾收集条件的对象

Java 符合垃圾收集条件的对象,java,scjp,Java,Scjp,这个问题是从我这里提出来的。有多少对象符合垃圾收集的条件 根据凯西·塞拉的回答,它是C。这意味着有两个对象可以进行垃圾收集。我已经解释了答案。但是为什么c3不符合(GC)条件 当到达//Do stuff时,有多少对象符合GC条件 A:0 B:1 C:2 D:编译失败 E:不可能知道 F:在运行时引发异常 答复: C是正确的。只有一个纸板对象(c1)符合条件,但它有一个关联的Shortwrapper对象也符合条件 A、 基于上述情况,B、D、E和F不正确。(目标7.4) c3为null,因此

这个问题是从我这里提出来的。有多少对象符合垃圾收集的条件

根据凯西·塞拉的回答,它是
C
。这意味着有两个对象可以进行垃圾收集。我已经解释了答案。但是为什么
c3
不符合(GC)条件

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

  • A:0
  • B:1
  • C:2
  • D:编译失败
  • E:不可能知道
  • F:在运行时引发异常
答复:

  • C是正确的。只有一个纸板对象(c1)符合条件,但它有一个关联的
    Short
    wrapper对象也符合条件
  • A、 基于上述情况,B、D、E和F不正确。(目标7.4)

c3
null
,因此那里显然没有符合垃圾收集条件的对象

请注意,只创建了两个
硬纸板
对象,这两个对象位于以下行:

CardBoard c1 = new CardBoard();
CardBoard c2 = new CardBoard();

在引用杂耍之后,其中只有一个没有引用。

从来没有
c3
指向的对象。构造函数只被调用了两次,两个对象,一个由
c1
c2
指向
c3
只是一个引用,除了空指针外,它从未被分配过任何东西

当前指向null的引用
c3
,不会超出范围并从堆栈中移除,直到主方法末尾的右括号被交叉


最初分配给
c1
的对象无法访问,因为
c1
引用被设置为null,但是
c2
引用尚未更改,因此分配给它的对象仍然可以通过
c2
引用从此范围访问。

如果您注意到代码中只创建了两个对象。c3从未初始化为对象,它是空引用。因此,只有一个“对象”符合垃圾收集的条件。

让我们逐行分解:

CardBoard c1 = new CardBoard();
我们现在有两个对象,
硬纸板
c1
指向和
c1.story
。这两种方法都不适用于GC,因为
c1
指向
carboard
carboard
变量的
story
指向
Short

CardBoard c2 = new CardBoard();
与上面类似,我们现在有四个对象,没有一个可用于GC

CardBoard c3 = c1.go(c2);
我们调用由
c1
指向的纸板上的方法go,传递
c2
的值,该值是对
纸板
对象的引用。我们将参数设为null,但Java是按值传递的,这意味着
c2
变量本身不受影响。然后返回空参数<代码>c3为
c1
c2
不受影响。我们仍然有4个对象,没有一个可以被GC'd

c1 = null;

我们为空
c1
。先前指向的
CardBoard
对象现在没有指向它的任何对象,可以对其进行GC。因为
CardBoard
对象中的
story
变量是指向
Short
的唯一对象,并且因为
CardBoard
对象符合GC的条件,所以
Short
也符合GC的条件。这给了我们4个对象,其中2个可以是GC'd。符合GC条件的对象是以前由
c1
c1引用的对象。story

形式上正确的答案是我们不知道。我们不知道的原因是这句话:

Short story = 200;
这将编译为以下字节码:

CardBoard();
Code:
   0: aload_0
   1: invokespecial #1                  // Method java/lang/Object."<init>":()V
   4: aload_0
   5: sipush        200
   8: invokestatic  #2                  // Method java/lang/Short.valueOf:(S)Ljava/lang/Short;
  11: putfield      #3                  // Field story:Ljava/lang/Short;
  14: return

更新:for
Short.valueOf()
比我引用的1.8版本更神秘,但同样的逻辑适用:仅仅通过查看代码无法判断是否将返回
Short
的新实例或缓存实例。

严格来说
c3
不符合GC条件,因为它不是一个对象。这是一个可以指向某个对象的变量。正确的答案是……有趣的是,有这么多的教程和练习讨论这类事情,但都是错误的。事实是,JVM根本不知道局部变量的范围。在过去,这通常意味着一些引用尽管超出范围,但没有被清除。今天,您可能会惊讶于这样一个事实:尽管对象“在范围内”,但它仍然被收集,请看…1)问题是关于java 6 2)如果不知道“//do stuff”可能包含什么内容,就无法推测编译器可能会对c2的未来可达性得出什么优化结论。java 6和java 8之间的规则没有改变。您甚至不能排除在实际的Java6实现中会发生这样的事情,只是,到目前为止还没有讨论过。如果您假设
//do stuff
可能包含与可达性相关的操作,那么正确的答案是问题不完整。这更证明了,这样的问题是多么毫无意义…
CardBoard();
Code:
   0: aload_0
   1: invokespecial #1                  // Method java/lang/Object."<init>":()V
   4: aload_0
   5: sipush        200
   8: invokestatic  #2                  // Method java/lang/Short.valueOf:(S)Ljava/lang/Short;
  11: putfield      #3                  // Field story:Ljava/lang/Short;
  14: return
Short story = new Short(200);