当前位置: 首页 > 面试题库 >

为什么在使用带有类名的静态变量时未显示非法前向引用错误

梁丘德寿
2023-03-14
问题内容

在下面的代码中,使用类名访问静态变量时,它不会引发前向引用错误,但是在不使用类名的情况下访问它会抛出正向引用错误。

为什么使用类名访问时不会发生这种情况?

class Test{
    static {
        System.out.println(a); // shows error
        a = 99; // and this line too doesn't give error  
        System.out.println(Test.a); // this line doesn't
    }
    static int a = 10;  
    static{
        System.out.println(a);
    }
}

问题答案:

前向引用规则在JLS§8.3.3中定义:

有时会限制使用声明后在文本上出现的类变量,即使这些类变量在范围内(第6.3节)。具体来说,如果满足以下所有条件,则是编译时错误:

  • 使用类变量后,将在文本或类C中声明类变量;

  • 在C的类变量初始值设定项或C的静态初始值设定项中,此名称是一个简单的名称;

  • 用法不在作业的左侧;

  • C是封闭使用的最里面的类或接口。

因此,基本上,您的first Sysout()满足以上所有四个条件,因此是编译时错误。

在2nd中Sysout(),您将a使用它的限定名称(而不是简单名称)进行访问,根据上面的规则,该名称是允许的。

现在,这样做的原因是,当您访问时Test.a,编译器将确保Test已加载类并且所有static字段均已初始化,因此它可以访问field
a。但是在访问a简单名称时,编译器不确定的初始化html" target="_blank">程序a是否已经运行,因为它可能仍在加载类中。

考虑以下加载类的过程:

  • 加载类时,将为其中static声明的所有变量分配内存。至此,变量a已经分配了内存(声明已完成)
  • 然后,所有static初始化程序都按照出现的顺序运行。
    • 第一个陈述是Sysout(a);a尚未初始化,因此您无法访问它。(错误)
    • 第二个陈述是a = 99。在这里,您实际上是在初始化变量a。很好。
    • 第三是Sysout(Test.a)-理由已经在上面发布。编译器知道Test已经加载。
    • 然后static int a = 10执行。它重新初始化a10。记住,声明部分已经在第一步中得到了照顾。


 类似资料:
  • 无论我怎么努力,我都会遇到这个问题。我尽了我所能。声明State类的对象时,显示错误“非静态变量,无法从静态上下文引用”

  • 问题内容: java为什么不能从静态环境引用非静态变量? 问题答案: 你必须了解一个类与该类实例之间的区别。如果你在街上看到汽车,即使你看不到哪种型号或类型,也将立即知道它是汽车。这是因为你将看到的与“汽车” 类进行了比较。该类包含与所有汽车相似的类。可以将其视为模板或想法。 同时,你看到的汽车是“汽车”类的一个实例,因为它具有你期望的所有属性:有人驾驶它,它有引擎,车轮。 因此,该班级说“所有汽

  • 问题内容: 我有一个非常简单的类,想用作另一个类的子类。但是,当我将其代码放入父类时,我得到: 非静态变量,不能从静态上下文中引用 另一方面,当我将sublass 的类代码放在“父母的”类代码之外时,我不会收到此错误。 为什么会这样呢? 问题答案: 嵌套类(顺便说一下,它 不是 子类)没有被标记为静态的,因此它是一个 内部 类,需要构造一个编码类(JavaApp1)的实例。 选项: 使嵌套类静态

  • 问题内容: 我试图编译其中一个Java类与拒绝 非法向前引用 错误,其中有问题的参考是词汇 后 的基准场。在显示相同行为时,将尽可能精简以下类: 并且的许多用途仅用作占位符,以删除不相关的代码段。 使用编译时,javac会显示以下错误消息: 因此,编译器抱怨的声明引用,而应在的声明范围内。但是,一旦删除了in 的声明的引用(例如,通过将第5行从更改为),编译器将接受该类。 如何解释呢?我对 前锋的

  • 可能重复: 不能从静态上下文(java)引用非静态变量 即使在这种情况下,我们也试图从静态方法访问非静态类。但这不会给出任何错误。为什么?

  • 我有一个非常简单的类,我想用它作为另一个类的子类。但当我将其代码放入父类时,我得到: 非静态变量,不能从静态上下文中引用 另一方面,当我将子类GenTest的类代码放在“父类”的类代码之外时,我没有得到这个错误。 为什么会发生这种情况?