为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

守候你守候我 2023-08-04 14:45:47
看看下面的代码: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 上找不到答案,所以我决定询问一下。
查看完整描述

4 回答

?
白板的微信

TA贡献1883条经验 获得超3个赞

§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中所示。



查看完整回答
反对 回复 2023-08-04
?
米脂

TA贡献1836条经验 获得超3个赞

第 16 章 明确分配

当发生对其值的任何访问时,每个局部变量(第 14.4 节)和每个空白最终字段(第 4.12.4 节、第 8.3.1.2 节)必须具有明确指定的值。

您尝试通过局部变量访问什么并不重要。规则是必须在此之前明确赋值。

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

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


查看完整回答
反对 回复 2023-08-04
?
慕的地10843

TA贡献1785条经验 获得超8个赞

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

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

System.out.println(Foo.x);

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


查看完整回答
反对 回复 2023-08-04
?
SMILET

TA贡献1796条经验 获得超4个赞

其他答案完美地解释了正在发生的事情背后的机制。也许您还想了解 Java 规范背后的基本原理。作为一个 Java 专家,我无法告诉你最初的原因,但让我指出这一点:

  • 每一段代码要么有意义,要么触发编译错误。

  • (对于静态,因为实例是不必要的,Foo.x所以很自然。)

  • 现在,我们该怎么办foo.x(通过实例变量访问)?

    • 这可能是一个编译错误,如 C# 中的错误,或者

    • 它有一个意义。因为Foo.x已经意味着“简单地访问”,所以该表达具有不同的含义x是合理的;也就是说,表达式的每个部分都是有效且可访问的。 foo.xx

希望有知情人士能说出真正的原因。:-)


查看完整回答
反对 回复 2023-08-04
  • 4 回答
  • 0 关注
  • 140 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信