我的问题与:
有关当我们的代码中出现类似内容时,会发生什么:
(new SomeClass()).longMethod();
是否还有某种未命名的(强?)引用指向堆放在堆上的新创建的对象?
如果Stack上没有任何内容,那么垃圾收集器如何知道在方法持续时间内保留对象?
是否可能与
相同{
// very local scope
SomeClass throwAwayRef = new SomeClass();
throwAwayRef.longMethod();
}
答案 0 :(得分:6)
您可以查看字节码以获取洞察力:
0: new #16 // class SomeClass
3: dup
4: invokespecial #18 // Method SomeClass."<init>":()V
7: invokevirtual #19 // Method SomeClass.longMethod:()V
new
实际上分配了对象,对象的引用被推送到堆栈上。 dup
复制堆栈顶部;现在,前两个堆栈项是对新创建的对象的引用。invokespecial
这里调用SomeClass
的构造函数,弹出堆栈;现在,堆栈只包含对SomeClass
实例的单个引用。该实例未进行GCed,因为堆栈上存在对它的引用。invokevirtual
来电longMethod
。同样,实例不是GCed,因为对它的引用仍然存在于堆栈上(并且在方法完成后弹出,之后 符合GC的条件)。(new SomeClass()).longMethod();
与
不同{
// very local scope
SomeClass throwAwayRef = new SomeClass();
throwAwayRef.longMethod();
}
在字节码级别,因为后者涉及astore
和aload
。但是,这两者肯定在功能上是等价的。 SomeClass
完成后,longMethod
实例仍符合GC条件(执行invokevirtual
时,两个代码段的堆栈看起来相同)。
<强>参考:强>
答案 1 :(得分:3)
是,
new SomeClass().longMethod();
实际上是相同的,特别是从垃圾收集的角度来看:
{
SomeClass throwAwayRef = new SomeClass();
throwAwayRef.longMethod();
}
内联版本具有对新对象的隐式引用(在堆栈上)。一旦方法调用结束,它就可用于垃圾收集。
答案 2 :(得分:1)
是的,堆栈上存在对新对象的引用。
直接来自Oracle:
要访问字段,您可以使用对象的命名引用,如 前面的示例,或者您可以使用任何返回的表达式 对象参考。回想一下new运算符返回一个引用 一个东西。所以你可以使用new返回的值来访问a 新对象的字段:
int height = new Rectangle().height;
此语句创建一个新的 Rectangle对象并立即获得其高度。从本质上讲, statement计算Rectangle的默认高度。 请注意 在此声明执行后,该程序不再具有 引用创建的Rectangle,因为程序从未存储过 任何地方的参考。该对象未被引用及其资源 可以通过Java虚拟机自由回收。
来源:https://docs.oracle.com/javase/tutorial/java/javaOO/usingobject.html