即使在实际启动变量之前,编译器是否可以为变量赋值?

时间:2011-05-10 02:45:38

标签: c# java vb.net compiler-construction initialization

我刚读过http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html?page=5,并说:

  

编译器可以自由地为singleton成员变量赋值   在单身人士的构造函数之前   称为

我想知道这是不是一个错字。他们真的真的想说: JVM的实现是免费的而不是编译器是免费的

我的第二个问题是我们是否也遇到过C#/ VB这个问题? (其中“”编译器“”可以在变量完全启动之前/甚至在变量类的构造函数完全运行之前为变量赋值。

2 个答案:

答案 0 :(得分:4)

在Java中,为对象分配内存并调用构造函数是两个独立的操作。例如,像

Object o = new Object();

编译成这些字节码:

0:  new #2; //class java/lang/Object
3:  dup
4:  invokespecial   #1; //Method java/lang/Object."<init>":()V
7:  astore_1

在指令0之后,堆栈上对已分配但未构造的对象的引用。直到偏移量4才会调用构造函数。绝对没有什么能阻止编译器将该引用分配给它想要的任何变量,包括静态成员。因此,这篇文章是正确的。

我不知道CLR字节码,但我想它与JVM的指令集非常接近,我猜这个运行时也存在与线程相关的警告。它当然适用于本机代码编译器。

答案 1 :(得分:1)

答案问题的第一部分是你是正确的,尽管这更像是一个草率的术语,而不是一个错字或错误。 (显然,编译器不会为变量赋值...这只会在执行编译器生成的代码时发生。)

技术上更准确的重述是:

“...因为编译器可以自由地生成代码,可能导致在调用单例的构造函数之前将值写入单例成员变量的内存中,并且构造的对象具有被冲到了记忆中。“

这种情况最有可能发生在本机代码编译器级别,当编译器(合法地)重新排序指令时,或者仅仅是内存流水线操作的结果。 Java内存模型特别允许这样,以便编译器能够生成在多核计算机上运行得更快的代码。 (另一方面,你的多线程代码必须以所需的方式同步,否则它可能不可靠。)

(理论上,字节码编译器也可以对字节码进行重新排序,但很有可能它不会。字节码编译器进行细粒度优化的价值很小。事实上,它可能是有害的,因为它可能是有害的使JIT编译器的优化器更难。)


我会将C#和VB案例留给熟悉这些语言规范的人。