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

时间:2012-02-09 08:05:50

标签: java bytecode bytecode-manipulation

我们的项目执行一些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;是必需的。

我的问题是:

  1. 是否有一些不同编译器之间差异的概述?文章/博客文章?
  2. 我能否安全地得出结论,如果没有&#34; dup&#34;介于&#34; new&#34;和&#34; invokespecial&#34;初始化后没有使用对象?

3 个答案:

答案 0 :(得分:6)

如果 invokespecial 之间存在 dup ,则编译后通常会使用 对象。例如,字段初始化通常是一系列 new dup invokespecial &amp;的 putfield 即可。但是,在您的示例中,最后一条指令是 pop ,它清除堆栈中的objectref - 这就是您可以假设不使用此对象的方式。

答案 1 :(得分:3)

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

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

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

玩得开心:)