Oracle和Eclipse编译器生成的java字节码的差异

我们的项目执行一些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."":(I)V 8: pop 9: return 

和Eclipse的编译器进入:

  0: new #15; //class java/lang/Integer 3: iconst_2 4: invokespecial #17; //Method java/lang/Integer."":(I)V 7: return 

如您所见,Oracle编译器在“new”之后生成“dup”,而Eclipse则不然。 在这个用例中完全正确,因为根本不使用新创建的Integer实例,因此不需要“dup”。

我的问题是:

  1. 是否对不同编译器之间的差异有一些概述? 文章/博文?
  2. 我可以安全地得出结论,如果“new”和“invokespecial”之间没有“dup”,那么在初始化之后不会使用对象吗?

  1. 我可以安全地得出结论,如果“new”和“invokespecial”之间没有“dup”,那么在初始化之后不会使用对象吗?

我不确定你的意思,但是对于创建的对象的引用可能会被构造函数存储在某处。 因此,调用方法可能在初始化后不使用该对象,但该对象可能仍然可以访问,因此可能不是垃圾可收集的。

如果newinvokespecial之间存在重复,通常在编译后使用该对象。 例如,字段初始化通常是newdupinvokespecialputfield的序列。 但是,在您的示例中,最后一条指令是pop ,它清除堆栈中的objectref – 这就是您可以假设不使用此对象的方式。

通过引用将打破这种模式

  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); } } 

玩的开心 :)