Ani*_*wat 16 java static-variables
我根本不理解以下代码的执行流程:
class Test {
static String s1 = getVal();
static String s2 = "S2";
private static String getVal() {
return s2;
}
public static void main(String args[]) {
System.out.println(s2); // prints S2
System.out.println(s1); // prints null
}
}
Run Code Online (Sandbox Code Playgroud)
它应该S2在第二个println声明打印.我更感兴趣的是理解为什么会发生这种情况而不是解决方案.
Sur*_*tta 16
静态事物按照它们在代码中出现的顺序执行.
static String s1 = getVal();
Run Code Online (Sandbox Code Playgroud)
所以从第一行开始,s1进行评估,到那时s2仍然是null.因此,您会看到null值.
Era*_*ran 13
static变量和static初始化程序块按照它们在源代码中出现的顺序进行初始化(除了static final在非最终static变量之前初始化的变量).
s1之前被初始化s2,因此调用getVal()返回默认值s2,即null.
您可以更改static变量的顺序以便首先初始化s2:
static String s2 = "S2";
static String s1 = getVal();
Run Code Online (Sandbox Code Playgroud)
强制初始化s2之前的另一种方法s1是进行s2最终:
static String s1 = getVal();
static final String s2 = "S2";
Run Code Online (Sandbox Code Playgroud)
以下是JLS 12.4.2中所述的初始化顺序的摘录.详细的初始化程序.与static变量相关的部分将突出显示.
对于每个类或接口C,存在唯一的初始化锁定LC.从C到LC的映射由Java虚拟机实现决定.初始化C的过程如下:
在C的初始化锁LC上同步.这涉及等到当前线程可以获取LC.
如果C的Class对象指示某个其他线程正在为C进行初始化,则释放LC并阻止当前线程,直到通知正在进行的初始化已完成,此时重复此步骤.
如果C的Class对象指示当前线程正在为C进行初始化,那么这必须是初始化的递归请求.释放LC并正常完成.
如果C的Class对象表明C已经初始化,则不需要进一步的操作.释放LC并正常完成.
如果C的Class对象处于错误状态,则无法进行初始化.释放LC并抛出NoClassDefFoundError.
否则,记录当前线程正在进行C的Class对象初始化并释放LC的事实.
然后,初始化C的静态字段,它们是常量变量(§4.12.4,§8.3.2,§9.3.1).
接下来,如果C是一个类而不是一个接口,那么让SC成为它的超类,让SI1,...,SIn成为C的所有超接口,声明至少一个默认方法.超接口的顺序由直接由C实现的每个接口的超接口层次结构上的递归枚举给出(以C的implements子句的从左到右的顺序).对于我直接由C实现的每个接口,在返回I之前,枚举在I的超接口上以I的extends子句的从左到右的顺序重复出现.
对于列表中的每个S [SC,SI1,...,SIn],如果S尚未初始化,则递归地执行S的整个过程.如有必要,首先验证并准备S.
如果S的初始化完成,因为突然抛出的异常的,然后获得LC,标注Class对象C作为错误,通知所有等待的线程,释放LC,并完成突然,扔了会导致从初始化S.同样的异常
接下来,通过查询其定义的类加载器来确定是否为C启用了断言(第14.10节).
接下来,按文本顺序执行类的类变量初始值设定项和类的静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样.
| 归档时间: |
|
| 查看次数: |
467 次 |
| 最近记录: |