【问题标题】:Why are non-static class variables initialiized at runtime and not compile time in Java为什么非静态类变量在运行时初始化而不是在Java中编译时
【发布时间】:2012-03-26 17:12:33
【问题描述】:

这是问题的延伸:Order of the initialization in Java

所以在代码块中:

public class Point {

int y = getX();
int x = 42;

int getX() { 
    return x; 
}

public static void main (String s[]) {
    Point p = new Point();
    System.out.println(p.x + "," + p.y);
}

}

它输出42,0

虽然上面的问题是通过描述 Java 编译器和运行时的行为来回答的,但它仍然困扰着我为什么编译器不将 x (42) 的初始值烘焙到字节码中? 我知道静态变量的值被嵌入到字节码中,因为它们是类级别的变量并且它们不占用对象内存中的任何空间,但是也为类级别的非静态变量嵌入任何初始值是否有意义也进入字节码?这样,上面的代码将更符合预期的行为,并且我猜测对象的实例化会更快(因为分配给 x 的内存将立即包含 42 因此节省解析类中初始化行的时间每次创建 Point 类的对象时)

我怀疑这可能与类字节码大小、对象初始化效率和编译时间效率之间的权衡有关。

我希望对 Java 编译器/运行时有深入了解的人可以对此有所了解。 了解框架内部的工作原理总能帮助我们编写更好的代码:-)

【问题讨论】:

  • 如果变量是对象会不会产生问题?当值为 42 时一切都很好,但如果该值是类 ComplexNumber 的对象怎么办?我们是否希望我们的所有点都引用相同的内存地址,并且本质上是相同的 ComplexNumber?现在我不是对 Java 编译器/运行时知识有深入了解的人,所以我在这里可能完全错了,但这是我能想到的最好理由。
  • 确实“将 x (42) 的初始值写入字节码”。你认为 x 怎么会变成 42 岁?在创建实例之前,它不会将其烘焙到 实例内存,因为没有实例内存。在运行时。你的问题没有意义。

标签: java jvm


【解决方案1】:

这不是效率问题;这是一个具有合理语义的问题。

Java 设计者希望无论x 被定义为42 还是getFortyTwo(),初始化的行为都相同,因为如果该行为不同,那么就会导致以各种方式无意中射中自己的脚。因此,他们在 JLS 中指定了字段初始化发生在哪个顺序字段中,并且该顺序独立x 是常量、方法调用还是土豆。 (作为参考,这是您声明字段的顺序——因此,如果您颠倒了班级中xy 的顺序,y 将设置为 42。)

坦率地说,我敢打赌编译器会将赋值 y = 0 烘焙到构造函数中,因为 JLS 的语义要求 y = 0 基于此代码。

【讨论】:

  • 有趣的是,我们选择了相同的例子“如果是这种情况,就会出现奇怪的行为”:)
  • 我并不感到惊讶。图书馆设计师(我认为包括我们俩在内的一个群体)倾向于根据“如果这是不同的/您建议的方式,那怎么会再次困扰您/导致意外行为?”这里的答案是,任何不是明显常量的东西都可能使语义混淆/出乎意料——非常量的最佳来源是方法调用。
【解决方案2】:

虽然通过描述 Java 编译器和运行时的行为回答了上述问题,但仍然困扰我为什么编译器不将 x (42) 的初始值烘焙到字节码中?

想象一下,如果你后来改变了这个:

int x = 42;

到这里:

int x = getInitialValueForX();

真的想要完全改变这种行为吗?

如果x真的只是一个常量,那么将其设为static final,它内联。事实上,如果一个变量 不是 final 并且 不是 静态的,那么我不明白为什么它应该被视为一个常量,即使初始值 恰好目前是一个常数。

【讨论】:

    【解决方案3】:

    我认为您误解了常量会发生什么,以及为什么。

    编译时常量可以内联,但通常静态变量不能。编译时常量是defined in the specification,,但简单地说,它是编译时已知的原始类型的值。有许多静态变量是用不是编译时常量的表达式初始化的。

    在这种情况下,PointgetX() 不是最终的,所以 getX() 的结果在编译时是未知的。当子类可以覆盖它并返回不同的值时,它怎么可能是内联的?

    【讨论】:

      猜你喜欢
      • 2021-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 2017-12-07
      • 2021-05-02
      • 1970-01-01
      相关资源
      最近更新 更多