为什么我们不能通过未初始化的局部变量访问静态内容?

看看下面的代码:

class Foo{
public static int x = 1;
}


class Bar{
public static void main(String[] args) {
Foo foo;
System.out.println(foo.x); // Error: Variable 'foo' might not have been initialized
}
}

正如您所看到的,当尝试通过 未初始化本地变量 Foo foo;代码访问静态字段 x时,会产生编译错误: Variable 'foo' might not have been initialized

这样的 似乎很强大错误是有意义的,但是只有当我们意识到访问 static成员时,JVM 实际上并不是 使用变量的 < strong > value ,而只是它的 < strong > type

例如,我可以用值 null初始化 foo,这样我们就可以毫无问题地访问 x:

Foo foo = null;
System.out.println(foo.x); //compiles and at runtime prints 1!!!

这样的场景之所以能够工作,是因为编译器认识到 x是静态的,并且将 foo.x看作是像 Foo.x一样编写的(至少我之前是这么认为的)。

那么为什么编译器突然坚持 foo的值应该是 它将不会使用呢?


免责声明: 这不是在实际应用中使用的代码,而是在 Stack Overflow 中找不到答案的有趣现象,所以我决定询问一下。

4099 次浏览

保持规则尽可能简单是有价值的,“不要使用可能没有被初始化的变量”就是这么简单。

更重要的是,有一种调用静态方法的既定方法——始终使用类名,而不是变量。

System.out.println(Foo.x);

变量“ foo”是不必要的开销,应该删除,编译器错误和警告可以被视为有助于实现这一点。

第16章确定转让

每个局部变量(14.4)和每个空白最终字段(4.12.4,8.3.1.2) 必须有一个明确分配的值时,它的值的任何访问发生。

通过本地变量访问 什么并不重要。规则是,它应该明确地分配之前。

为了评估 字段访问表达式 foo.x,必须首先评估它的 primary部分(foo)。这意味着将发生对 foo的访问,这将导致编译时错误。

对于局部变量或空白 final 字段 x 的每次访问,必须在访问之前明确地分配 x,即 或发生编译时错误。

15.11字段访问表达式 :

如果字段为 静电干扰:

计算主表达式,并丢弃结果 。如果主表达式的计算突然完成,字段访问表达式也会因为同样的原因突然完成。

前面说明字段访问是由 Primary.Identifier标识的。

这表明,即使它似乎没有使用 Primary,它仍然被计算,然后结果被丢弃,这就是为什么它将需要被初始化。当计算按照引号中的说明停止访问时,这可能会产生不同的结果。

编辑:

下面是一个简短的例子,可以直观地证明,即使结果被丢弃,Primary也会被评估:

class Foo {
public static int x = 1;
    

public static Foo dummyFoo() throws InterruptedException {
Thread.sleep(5000);
return null;
}
    

public static void main(String[] args) throws InterruptedException {
System.out.println(dummyFoo().x);
System.out.println(Foo.x);
}
}

这里您可以看到,dummyFoo()仍然被计算,因为 print被延迟了5秒 Thread.sleep(),尽管它总是返回一个被丢弃的 null值。

如果没有计算表达式,print将立即出现,这可以在使用类 Foo直接访问 Foo.xx时看到。

注意: Method 调用也被认为是 15.8主要表达式中显示的 Primary

其他答案完美地解释了这一切背后的机制。也许您还想知道 Java 规范背后的基本原理。由于我不是 Java 专家,所以我不能给出最初的原因,但是让我指出这一点:

  • 每段代码要么有意义,要么触发编译错误。
  • (对于静态,因为实例是不必要的,所以 Foo.x是自然的。)
  • 现在,我们应该如何处理 ABc0(通过实例变量访问) ?
    • 它可能是一个编译错误,比如 C # ,或者
    • 它是有意义的。因为 Foo.x已经意味着“简单地访问 x”,所以 表情 foo.x有不同的含义是合理的,即 表达式的每个部分都是有效的和访问 x

让我们希望有知识渊博的人能告诉我们真正的原因: -)