【问题标题】:Default variables' values vs initialization with default默认变量的值与默认初始化
【发布时间】:2013-01-17 19:14:49
【问题描述】:

我们都知道,根据JLS7 p.4.12.5,每个实例变量都被初始化为默认值。例如。 (1):

public class Test {
    private Integer a;  // == null
    private int b;      // == 0
    private boolean c;  // == false
}

但我一直认为,这样的类实现(2):

public class Test {
    private Integer a = null;
    private int b = 0;
    private boolean c = false;
}

绝对等于示例 (1)。我预计,那个复杂的 Java 编译器会看到 (2) 中的所有这些初始化值都是多余的并忽略它们。

但是突然对于这两个类,我们有两个不同的字节码。

例如(1):

   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

例如(2):

   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aconst_null
   6:   putfield    #2; //Field a:Ljava/lang/Integer;
   9:   aload_0
   10:  iconst_0
   11:  putfield    #3; //Field b:I
   14:  aload_0
   15:  iconst_0
   16:  putfield    #4; //Field c:Z
   19:  return

问题是:为什么?但这显然是需要优化的事情。是什么原因?

UPD:我使用 Java 7 1.7.0.11 x64,没有特殊的 javac 选项

【问题讨论】:

  • 如果启用优化(如果我没记错的话)-O,结果是否相同?
  • 它是-O(大写),不过只是经过测试,并没有被优化掉。

标签: java bytecode compiler-optimization


【解决方案1】:

不,它们不相等。在对象实例化时立即分配默认值。字段初始值设定项中的赋值发生在调用超类构造函数时...这意味着您可以在某些情况下看到差异。示例代码:

class Superclass {
    public Superclass() {
        someMethod();
    }

    void someMethod() {}
}

class Subclass extends Superclass {
    private int explicit = 0;
    private int implicit;

    public Subclass() {
        System.out.println("explicit: " + explicit);
        System.out.println("implicit: " + implicit);
    }

    @Override void someMethod() {
        explicit = 5;
        implicit = 5;
    }
}

public class Test {
    public static void main(String[] args) {
        new Subclass();
    }
}

输出:

explicit: 0
implicit: 5

在这里您可以看到,在Superclass 构造函数完成后但在子类构造函数body 执行之前,显式字段初始化将explicit 的值“重置”回0。 implicit 的值仍然具有从 Superclass 构造函数对 someMethod 的多态调用中分配的值。

【讨论】:

  • @JoachimIsaksson:当你在真实代码中被它咬过时很容易记住;)
  • 是的......在这种情况下,编译器应该能够优化,因为没有要考虑的基类。还是我错过了什么?
  • @JoachimIsaksson:我认为javac 执行此优化是错误的。我认为,字节码更紧密地表示源代码要好得多。 JIT 编译器可能会对其进行优化。
  • 这是否也适用于 C#?
  • @Joachim,即使这是有效的,Java 编译器也几乎不会优化任何东西。这就是反编译如此简单的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
  • 2014-05-06
  • 2012-11-29
  • 2010-09-13
  • 1970-01-01
相关资源
最近更新 更多