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."<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"。

我的问题是:

  1. 是否概述了不同编译器之间的差异?一篇文章/博客
  2. 我可以放心地得出结论,如果"new"one_answers"invokespecial"之间没有"dup",那么初始化后就不会使用对象了吗

如果newinvokespecial之间存在dup,则对象通常在编译后使用。例如,字段初始化通常是newdupinvokespecial&putfield。然而,在您的示例中,最后一条指令是pop,它从堆栈中清除objectref——这就是您可以假设没有使用此对象的方式。

  1. 我可以放心地得出结论,如果"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);
    }
  }

玩得开心:)

最新更新