Java 为什么在使用类名为的静态变量时未显示非法的前向引用错误
在下面的代码中,当访问具有类名的静态变量时,它不会抛出前向引用错误,但在没有类名的情况下访问它会抛出前向引用错误 为什么使用类名访问时不会发生这种情况Java 为什么在使用类名为的静态变量时未显示非法的前向引用错误,java,Java,在下面的代码中,当访问具有类名的静态变量时,它不会抛出前向引用错误,但在没有类名的情况下访问它会抛出前向引用错误 为什么使用类名访问时不会发生这种情况 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 l
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);
}
}
类初始值设定项是在加载类时运行的,您无法确定何时会发生这种情况。在类初始值设定项中运行的代码应该只用于需要处理或“初始化”以使其他静态方法(或类本身)正常工作的事情 此外,您正在引用尚未声明的变量。在类初始值设定项(第一个静态块)中,您指定了
a=99
,但尚未声明a。如果您想要声明变量,然后在静态块中初始化它
没有理由对发布的代码类型使用类初始值设定项。这应该是一个静态方法
这里有一个例子
class Test{
static int a = 10;
static void doSomething(){
System.out.println(a);
a = 99;
System.out.println(a);
}
}
然后主要可以调用
Test.doSomething()代码>那么,静态块
static {
System.out.println(a);
a = 99;
System.out.println(Test.a);
}
将在声明a
之前执行
带有Test.a
的行不会触发任何错误,因为编译器检查并找到在类Test
中声明的静态变量a
,正向引用的规则定义如下:
使用类变量,其声明以文本形式显示在
使用有时会受到限制,即使这些类变量在
范围(§6.3)。具体来说,如果所有
以下是事实:
- 此时会出现类或接口C中的类变量声明
使用类变量后的文本形式
- 在C的类变量初始值设定项中使用一个简单的名称
或C的静态初始值设定项
- 使用不在作业的左侧
- C是包含该用法的最内层类或接口
因此,基本上您的第一个Sysout()
,满足上述所有4个条件,因此这是一个编译时错误
在第二个Sysout()
中,您使用的是a
的限定名称,而不是简单名称,根据上述规则,这是允许的
现在,这样做的原因是,当您访问Test.a
时,编译器确保Test
类已加载,并且所有静态
字段都已初始化,因此它可以访问a
字段。但是当在简单名称上访问a
时,编译器不确定a
的初始值设定项是否已经运行,因为它可能仍在加载类的过程中
考虑以下类的加载过程:
- 加载类时,将为其中声明的所有
静态
变量分配内存。此时,变量a
已分配内存(声明已完成)
- 然后,所有的
静态
初始值设定项都按照出现的顺序运行。
- 第一个语句是
Sysout(a)代码><代码>a
尚未初始化,因此您无法访问它。(错误)
- 第二条语句是
a=99
。这里实际上是初始化变量a
。很好
- 第三个是
Sysout(Test.a)
——上面已经给出了这方面的理由。编译器知道测试已加载
- 然后执行
static int a=10
。它将a
重新初始化为10
。记住,声明部分已经在第一步中处理好了
首先,让我们看看非法转发引用应该怎么说
使用类变量,其声明以文本形式显示在
使用有时会受到限制,即使这些类变量在
范围(§6.3)。具体来说,如果所有
以下是事实:
此时会出现类或接口C中的类变量声明
使用类变量后的文本形式
在C的类变量初始值设定项中使用一个简单的名称
或C的静态初始值设定项
使用不在作业的左侧
C是包含该用法的最内层类或接口
使用实例变量,其声明以文本形式显示在
即使这些实例变量
都在范围之内。具体来说,如果所有
以下是事实:
类或接口C中实例变量的声明
在使用实例变量后以文本形式显示
在实例变量初始值设定项或
C或C的实例初始值设定项
使用不在作业的左侧
C是包含该用法的最内层类或接口
它为每个静态变量和实例变量定义了什么是非法的正向引用。然而,两者的定义似乎是相同的。既然你的问题是关于静态的,我们只会深入探讨这个问题
1) 请参阅,对于静态变量,有声明
和初始化
static int a; //only declaration
static int b = 10; //both declaration and initialization
2) 如果类变量的声明在使用后以文本形式出现,则有时会受到限制,即使这些类变量在范围内
它向我们解释了什么?它说,在某些情况下,我们可以使用静态变量,即使我们在事后声明它们。在某些情况下,这是不允许的。那么,有哪些情况是不允许这样做的
如果以下4个条件同时为真。否则你可以自由使用它
a) The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
b) The use is a simple name in either a class variable initializer of C or a static initializer of C;
c) The use is not on the left hand side of an assignment;
d) C is the innermost class or interface enclosing the use.
class Test {
static {
System.out.println(a); // True + True + True +True ; Illegal forward reference
a = 99; // True + True + False +True ; No illegal forward reference
System.out.println(Test.a); // True + False + True + True No illegal forward reference
}
static int a = 10;
static {
System.out.println(a);
}
}
class Test {
static {
System.out.println(Test.a); // prints 0
a = 99; // a get 99
System.out.println(Test.a); // prints 99
}
static int a = 10;
static {
System.out.println(a); // prints 10
}
public static void main(String[] args) {
}
}