12

我们的项目做了一些 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”和“invokespecial”之间没有“dup”,那么初始化后不使用对象吗?
4

3 回答 3

6

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

于 2012-02-09T08:19:55.957 回答
3
  1. 我可以安全地得出结论,如果“new”和“invokespecial”之间没有“dup”,那么初始化后不使用对象吗?

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

于 2012-02-09T08:37:29.493 回答
1

传递这个引用会稍微打破这个模式

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

玩得开心 :)

于 2012-02-09T08:57:48.170 回答