Java静态与实例变量illegal forward reference问题及初始化顺序咨询
Java初始化顺序与左值规则说明
1. 初始化执行顺序
Java的静态和实例初始化逻辑都遵循按代码书写顺序执行的规则,分为两个维度:
- 类初始化阶段(类加载时触发一次):按代码先后顺序执行所有静态初始化块、静态变量声明赋值操作。你示例中的静态块写在
static int i; static int k;之前,所以静态块的执行时机早于两个静态变量的显式声明步骤。 - 实例初始化阶段(每次创建实例时触发):按代码先后顺序执行所有实例初始化块、实例变量声明赋值操作,最后执行构造方法。你示例中的实例块写在
String thisString; int b;之前,所以实例块的执行时机早于两个实例变量的显式声明步骤。
2. 左值规则的应用
你遇到的「赋值合法、取值报错」就是Java前向引用限制的左值例外规则,具体规则如下:
如果成员变量的使用场景是赋值表达式的左值(即作为被赋值的对象),哪怕写在变量声明之前也不会触发非法前向引用报错;如果是作为右值(即读取变量值使用),且没有加类名/this前缀限定,就会触发编译报错。
规则原理
JVM在类加载/实例创建的最早期就会给所有成员变量分配内存空间,默认初始化为对应类型的零值(int为0,引用类型为null):
- 你写
b=0;的时候只是往已经分配好的内存空间写入值,不需要依赖变量的声明顺序,所以合法。 - 你写
System.out.println(thisString+b)的时候是要读取两个变量的值,此时编译器还没有完成两个变量的符号注册,默认不允许直接读取,所以报非法前向引用错误。
如果确实需要在声明前读取变量值,可以加显式前缀绕过限制,修改后代码可正常编译:
static { System.out.println("Static Initializer"); i = 1; k = 2; // 加类名前缀显式指定访问静态成员 System.out.println(IntitializeTest.i+" "+IntitializeTest.k); } { System.out.println("Instance Initializer"); thisString = " empty "; b = 0; // 加this前缀显式指定访问实例成员 System.out.println(this.thisString+this.b); }
内容的提问来源于stack exchange,提问作者Abhivanth
相关产品推荐
相关产品推荐

