类A
包含:
- 静止的
Strings
- 填充在类的静态
Map
块中的静态 - 一个静态方法,例如
getStr()
,它返回String
从静态构建的Strings
类B
包含:
- 一个静态的
Map
- 填充
Map
using的静态块A.getStr()
B
的静态块总是能成功填充它的地图吗?我假设JVM能够处理这个。加载类时执行静态块的顺序是否存在任何问题,这反过来又不能保证B
正确填充地图?我想确定,也许了解这背后的机制。
类A
包含:
Strings
Map
块中的静态getStr()
,它返回String
从静态构建的
Strings
类B
包含:
Map
Map
using的静态块A.getStr()
B
的静态块总是能成功填充它的地图吗?我假设JVM能够处理这个。加载类时执行静态块的顺序是否存在任何问题,这反过来又不能保证B
正确填充地图?我想确定,也许了解这背后的机制。
如果两个类在静态初始化期间具有循环依赖关系,事情就会变得棘手。Java 确实有一个严格定义的初始化过程,并在检测到递归时退出。但是,这将取决于在运行时首先触发哪个类初始化。这意味着部分初始化的类可能是可见的(在您的情况下,看到 null getStr
)。
如果从两个不同的线程初始化两个类,循环依赖不仅令人困惑,甚至可能导致死锁。因此,应该不惜一切代价避免它。两方之间的循环依赖总是可以通过引入第三方来解决。
没有循环依赖,一个类总是被完全初始化;在您的情况下,当 B 调用时A.getStr()
,它必须A
是完全初始化的情况,并getStr()
返回所需的值。
作为循环依赖的一个例子,假设class A extends B
.
如果B
先初始化(例如有人调用B.something
),则没有问题;B初始化过程中遇到A.getStr
,会触发A初始化;完成后,A.getStr
然后执行,并看到一个正确初始化的字段。
但是,如果A
是先初始化,那就麻烦了;它将触发超类 B 的初始化;当 B 调用时A.getStr
,VM 看到它A
已经在初始化过程中,所以它会后退并且不会尝试完成 A 的初始化;A.getStr
将简单地看到null
。
为了打破这个循环,我们可以将 A 中 B 依赖的东西移动到 A'。A 和 B 都取决于 A'。