Java中静态final字段的初始化

发布于 2024-11-07 04:04:51 字数 417 浏览 0 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

深白境迁sunset 2024-11-14 04:04:51

这是一个排序问题。静态字段按照遇到的顺序进行初始化,因此当您调用 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.

会傲 2024-11-14 04:04:51

JLS 8.3.2.3“初始化期间使用字段的限制”。

JLS 规则允许在您的问题中使用,并声明第一次调用 getc() 将返回 alex 的默认(未初始化)值。

然而,规则不允许使用某些未初始化的变量;例如

int i = j + 1;
int j = i + 1;

是不允许的。


回复一些其他答案。这并不是Java编译器“想不通”的情况。编译器严格执行 Java 语言规范指定的内容。 (或者换句话说,可以编写一个编译器来检测示例中的循环并将其称为编译错误。但是,如果这样做,它将拒绝有效的 Java 程序,并且因此不会是一个符合标准的 Java 编译器。)


在评论中,您声明了这一点:

...final 字段始终必须在编译时或在对象创建之前的运行时初始化。

这是不正确的。

实际上有两种 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 of alex.

However, the rules disallow some uses of uninitialized variables; e.g.

int i = j + 1;
int j = i + 1;

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:

... final fields always must be initialized at compile or at runtime before the object creation.

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 on final variables is that they must be initialized once and only once during class initialization (for a static) 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.

香草可樂 2024-11-14 04:04:51

值不是编译时常量表达式的静态最终字段按声明顺序初始化。因此,当alex初始化时,alex1尚未初始化,因此getc()返回alex1的默认值>(<代码>0)。

请注意,在以下情况下,结果会有所不同 (10 10 10):

static final int alex1 = 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 that getc() returns default values of alex1 (0).

Note that result will be different (10 10 10) in the following case:

static final int alex1 = 10;

In this case alex1 is initialized by a compile-time constant expression, therefore it's initialized from the very beginning.

败给现实 2024-11-14 04:04:51

静态字段没有什么特别之处,只是编译器无法判断您正在使用可以在初始化之前访问字段的方法。

例如

public class Main {
    private final int a;

    public Main() {
        System.out.println("Before a=10, a="+getA());
        this.a = 10;
        System.out.println("After a=10, a="+getA());
    }

    public int getA() {
        return a;
    }

    public static void main(String... args) {
        new Main();
    }
}

印刷品

Before a=10, a=0
After a=10, a=10

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.

public class Main {
    private final int a;

    public Main() {
        System.out.println("Before a=10, a="+getA());
        this.a = 10;
        System.out.println("After a=10, a="+getA());
    }

    public int getA() {
        return a;
    }

    public static void main(String... args) {
        new Main();
    }
}

prints

Before a=10, a=0
After a=10, a=10
逆流 2024-11-14 04:04:51

类变量不需要初始化,它们会自动设置为其默认值。如果是基元(如 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文