我们的项目执行一些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编译器在"new"之后生成"dup",而Eclipse不生成。这在这个用例中是完全正确的,因为新创建的Integer实例根本没有使用,所以不需要"dup"。
我的问题是:
- 是否概述了不同编译器之间的差异?一篇文章/博客
- 我可以放心地得出结论,如果"new"one_answers"invokespecial"之间没有"dup",那么初始化后就不会使用对象了吗
如果new和invokespecial之间存在dup,则对象通常在编译后使用。例如,字段初始化通常是new、dup和invokespecial&putfield。然而,在您的示例中,最后一条指令是pop,它从堆栈中清除objectref——这就是您可以假设没有使用此对象的方式。
- 我可以放心地得出结论,如果"new"one_answers"invokespecial"之间没有"dup",那么初始化后就不会使用对象了吗
我不确定到底是什么意思,但对创建的对象的引用可能由构造函数存储在某个地方。因此,调用方法可能在初始化后不使用该对象,但该对象可能仍然是可访问的,因此可能不可垃圾回收。
通过此引用将稍微打破此模式
public class Bump {
Test t;
public Bump() {
new Test(this);
}
public void setT(Test t) {
this.t = t;
}
}
然后可以使用这个来存储结果:)
public class Test {
Bump b;
public Test(Bump b) {
this.b = b;
b.setT(this);
}
}
玩得开心:)