java - 为什么我在初始化期间可以引用静态字段来写入,但不能读取?

标签 java

所以我只是编程了一下,当我遇到一些非常不想要的行为并发现一些关于 Java 的非常奇怪的事情时。让我们看一下(精简的)代码:

public class Main {

    static{
        test = "test2";           // this is fine!?
        System.out.println(test); //compilation error!
    }

    static String test = "test1"; // initialization line

    public static void main(String[] args) {
        System.out.println(test);
    }
}

这个程序给你一个编译时错误,指出你不能在定义之前引用“test”。然而我之前只做了一行。现在猜猜当您注释掉错误行时,输出是什么...

输出是:“test1”,因此初始化会覆盖声明之前发生的赋值!

此外,如果您不初始化变量,则输出为“test2”。但是,如果您在初始化期间显式指定“null”作为值,则输出将为“null”。

问题:

  1. 为什么在声明变量之前我可以访问要写入的变量,但不能读取该变量?
  2. 为什么初始化是在第一次赋值之后完成的(这与术语“初始化”相矛盾)?
  3. 我一直认为用“null”显式初始化与省略初始化是一样的。这个例子显然是错误的。我只是想错了还是这与规范相矛盾?
  4. 这真的是想要的 Java 行为吗?这是一个错误吗?

最佳答案

这是 JLS 中定义的预期行为。回答您的问题:

  1. Why can I access a variable to write, but not to read, before it is declared?

section 8.3.2.3 回答了这个问题

The declaration of a member needs to appear textually before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold:

  • The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.

  • The usage is not on the left hand side of an assignment.

  • The usage is via a simple name.

  • C is the innermost class or interface enclosing the usage.

It is a compile-time error if any of the four requirements above are not met.

因此,由于赋值位于赋值的左侧,因此它显然不是引用必须位于声明之后的情况之一。

  1. Why is the initialization done after the first assignment (this contradicts the term "initialization")?

section 12.4.2 回答了这个问题.

Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

所有初始化都像在静态初始化 block 内一样发生,按照相对于每个其他初始化或静态 block 出现的顺序。该字段以默认值 null 开始,在静态 block 中使用,然后进行初始化。

  1. I always thought that explicitly initializing with "null" is the same as omitting the initialization. This is obviously wrong with this example... was I just thinking the wrong thing or does this contradict the spec?

由于您在此处看到的原因,这并不完全相同。如果在初始化发生之前修改静态 block 中的值,它将在静态初始化阶段设置回 null。

  1. Is this really the wanted Java behavior? Is it a bug?

是的,这是想要的行为。正如上面链接的 JLS 部分所示,这不仅仅是一个意外的事情。有关它的规则明确规定允许这样做。

关于java - 为什么我在初始化期间可以引用静态字段来写入,但不能读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40890099/

相关文章:

java - Java 更新后 jZe​​bra 加载错误

java - 将 JAXB 注释类用于 JAXWS 服务

java - 我怎样才能在java中转换这个xml文档?

java - Thorntail 中 MicroProfile Config 实现的可移植性问题

java - 快速排序三中位数

java - Neo4j Spring SocketTimeoutError 错误

java - 如何在用户可见时加载一个 fragment 数据并在加载一次后保留数据

java - 输入不匹配错误

java子类打印参数默认值而不是赋值

java - 异步 Servlet 不在单独的线程中执行异步任务