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

看看下面的代码:


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

    }

}

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


这个错误看起来似乎是有道理的,但只有当我们意识到要访问成员时,staticJVM 实际上并不使用变量的值,而只使用其类型。


例如,我可以foo使用值进行初始化null,这将使我们可以x毫无问题地访问:


Foo foo = null;

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

这种情况之所以有效,是因为编译器意识到它x是静态的,并把foo.x它当作是这样写的Foo.x(至少到目前为止我是这么认为的)。


那么为什么编译器突然坚持使用一个它根本不会使用的foo值呢?


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


守候你守候我
浏览 141回答 4
4回答

白板的微信

§15.11。字段访问表达式:如果该字段是静态的:对 Primary 表达式进行求值,并丢弃结果。如果主表达式的求值突然完成,则字段访问表达式也会出于同样的原因突然完成。之前它指出字段访问由 标识 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类访问时看到 。FooxFoo.x注意: 方法调用也被视为§15.8 主表达式Primary中所示。

米脂

第 16 章 明确分配当发生对其值的任何访问时,每个局部变量(第 14.4 节)和每个空白最终字段(第 4.12.4 节、第 8.3.1.2 节)必须具有明确指定的值。您尝试通过局部变量访问什么并不重要。规则是必须在此之前明确赋值。要计算字段访问表达式 foo.x,必须首先计算primary它的部分 ( )。foo这意味着将发生访问foo,这将导致编译时错误。对于局部变量或空白最终字段 x 的每次访问,必须在访问之前明确分配 x,否则会发生编译时错误。

慕的地10843

保持规则尽可能简单是有价值的,“不要使用可能尚未初始化的变量”就这么简单。更重要的是,有一种调用静态方法的既定方法 - 始终使用类名,而不是变量。System.out.println(Foo.x);变量“foo”是不需要的开销,应该被删除,编译器错误和警告可以被视为有助于实现这一点。

SMILET

其他答案完美地解释了正在发生的事情背后的机制。也许您还想了解 Java 规范背后的基本原理。作为一个 Java 专家,我无法告诉你最初的原因,但让我指出这一点:每一段代码要么有意义,要么触发编译错误。(对于静态,因为实例是不必要的,Foo.x所以很自然。)现在,我们该怎么办foo.x(通过实例变量访问)?这可能是一个编译错误,如 C# 中的错误,或者它有一个意义。因为Foo.x已经意味着“简单地访问”,所以该表达具有不同的含义x是合理的;也就是说,表达式的每个部分都是有效且可访问的。 foo.xx希望有知情人士能说出真正的原因。:-)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java