我们的项目执行一些Java字节码检测。我们偶然发现了一些奇怪的行为。假设以下代码片段:
public void a() {
new Integer(2);
}
Oracle的javac将上述内容编译为以下字节码:
0: new #2; //class java/lang/Integer
3: dup
4: iconst_2
5: invokespecial #3; //Method java/lang/Integer."<init>":(I)V
8: pop
9: return
和Eclipse的编译器进入:
0: new #15; //class java/lang/Integer
3: iconst_2
4: invokespecial #17; //Method java/lang/Integer."<init>":(I)V
7: return
正如您所看到的,Oracle编译器生成&#34; dup&#34;在&#34; new&#34;之后,而Eclipse并没有。这个用例完全正确,因为根本没有使用新创建的Integer实例,所以没有&#34; dup&#34;是必需的。
我的问题是:
答案 0 :(得分:6)
如果新和 invokespecial 之间存在 dup ,则编译后通常会使用 对象。例如,字段初始化通常是一系列 new , dup , invokespecial &amp;的 putfield 即可。但是,在您的示例中,最后一条指令是 pop ,它清除堆栈中的objectref - 这就是您可以假设不使用此对象的方式。
答案 1 :(得分:3)
- 我可以安全地断定,如果“new”和“invokespecial”之间没有“dup”,那么初始化后不会使用对象吗?
醇>
我不确定你的意思完全,但是对于创建的对象的引用可能会被构造函数存储在某处。因此,调用方法可能在初始化后不使用该对象,但该对象可能仍然可以访问,因此可能不是垃圾可收集的。
答案 2 :(得分:1)
传递此引用会稍微破坏此模式
public class Bump {
Test t;
public Bump() {
new Test(this);
}
public void setT(Test t) {
this.t = t;
}
}
然后可以使用 this 来存储结果:)
public class Test {
Bump b;
public Test(Bump b) {
this.b = b;
b.setT(this);
}
}
玩得开心:)