Java中静态final字段的初始化
public class Main {
static final int alex=getc();
static final int alex1=Integer.parseInt("10");
static final int alex2=getc();
public static int getc(){
return alex1;
}
public static void main(String[] args) {
final Main m = new Main();
System.out.println(alex+" "+alex1 +" "+alex2);
}
}
有人能告诉我为什么打印:0 10 10
吗?我知道它是一个静态最终变量,它的值不应该改变,但理解编译器如何初始化字段有点困难。
public class Main {
static final int alex=getc();
static final int alex1=Integer.parseInt("10");
static final int alex2=getc();
public static int getc(){
return alex1;
}
public static void main(String[] args) {
final Main m = new Main();
System.out.println(alex+" "+alex1 +" "+alex2);
}
}
Can someone tell me why this prints: 0 10 10
? I understand that it's a static final variable and its value shouldn't change but it`s a little difficult to understand how the compiler initializes the fields.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是一个排序问题。静态字段按照遇到的顺序进行初始化,因此当您调用 getc() 来初始化 alex 变量时,alex1 尚未设置。您需要先对 alex1 进行初始化,然后才能得到预期的结果。
It's an ordering problem. Static fields are initialized in the order that they are encountered, so when you call getc() to inititalize the alex variable, alex1 hasn't been set yet. You need to put initialization of alex1 first, then you'll get the expected result.
JLS 8.3.2.3“初始化期间使用字段的限制”。
JLS 规则允许在您的问题中使用,并声明第一次调用
getc()
将返回alex
的默认(未初始化)值。然而,规则不允许使用某些未初始化的变量;例如
是不允许的。
回复一些其他答案。这并不是Java编译器“想不通”的情况。编译器严格执行 Java 语言规范指定的内容。 (或者换句话说,可以编写一个编译器来检测示例中的循环并将其称为编译错误。但是,如果这样做,它将拒绝有效的 Java 程序,并且因此不会是一个符合标准的 Java 编译器。)
在评论中,您声明了这一点:
这是不正确的。
实际上有两种
final
字段:所谓的“常量变量”确实在编译时求值。 (常量变量是“原始类型或 String 类型的变量,它是最终的并使用编译时常量表达式初始化” - 请参阅 JLS 4.12.4。)。这样的字段在您访问它时始终会被初始化......对此处不相关的某些复杂性进行模数。
其他
final
字段按照JLS指定的顺序进行初始化,并且可以在初始化之前看到字段的值。对final
变量的限制是它们必须在类初始化期间(对于static
)或期间<期间初始化一次且仅一次。 /em> 对象初始化。最后,这个东西是非常“极端”的行为。典型的写得好的课程不需要
在初始化之前访问
final
字段。This situation is covered by JLS 8.3.2.3 "Restrictions on the use of Fields during Initialization".
The JLS rules allows the usage in your Question, and state that the first call to
getc()
will return default (uninitialized) value ofalex
.However, the rules disallow some uses of uninitialized variables; e.g.
is disallowed.
Re some of the other answers. This is not a case where the Java compiler "can't figure it out". The compiler is strictly implementing what the Java Language Specification specifies. (Or to put it another way, a compiler could be written to detect the circularity in your example and call it a compilation error. However, if it did this, it would be rejecting valid Java programs, and therefore wouldn't be a conformant Java compiler.)
In a comment you state this:
This is not correct.
There are actually two kinds of
final
fields:A so-called "constant variable" is indeed evaluated at compile time. (A constant variable is a variable "of primitive type or type String, that is final and initialized with a compile-time constant expression" - see JLS 4.12.4.). Such a field will always have been initialized by the time you access it ... modulo certain complications that are not relevant here.
Other
final
fields are initialized in the order specified by the JLS, and it is possible to see the field's value before it has been initialized. The restriction onfinal
variables is that they must be initialized once and only once during class initialization (for astatic
) or during object initialization.Finally, this stuff is very much "corner case" behavior. A typical well-written class won't need to
access a
final
field before it has been initialized.值不是编译时常量表达式的静态最终字段按声明顺序初始化。因此,当
alex
初始化时,alex1
尚未初始化,因此getc()
返回alex1
的默认值>(<代码>0)。请注意,在以下情况下,结果会有所不同 (
10 10 10
):在这种情况下,
alex1
由编译时常量表达式初始化,因此它是从最开始初始化的开始。Static final fields whose values are not compile-time constant expressions are initialized in order of declaration. Thus when
alex
in being initialized,alex1
is not initialized yet, so thatgetc()
returns default values ofalex1
(0
).Note that result will be different (
10 10 10
) in the following case:In this case
alex1
is initialized by a compile-time constant expression, therefore it's initialized from the very beginning.静态字段没有什么特别之处,只是编译器无法判断您正在使用可以在初始化之前访问字段的方法。
例如
印刷品
There is nothing special about static fields, it just that the compiler cannot workout that you are using a method which can access a field before its initialised.
e.g.
prints
类变量不需要初始化,它们会自动设置为其默认值。如果是基元(如 int、short...),则为 0(零);如果是对象,则为
null
。因此 alex1 设置为 0。
方法变量必须初始化,否则会出现编译错误。
要获得更好的解释,请阅读 http://download.oracle.com/javase/教程/java/javaOO/classvars.html
Class variables are not necessary to initialize, they are automatically set to their default values. If primitives (like int, short...) it's 0 (zero) for Objects it's
null
.Therefore alex1 is set to 0.
Method variables must be initialized, otherwise you will get an compiliation error.
For a better explanation read http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html