类A包含:
- 静止的
Strings - 填充在类的静态
Map块中的静态 - 一个静态方法,例如
getStr(),它返回String从静态构建的Strings
类B包含:
- 一个静态的
Map - 填充
Mapusing的静态块A.getStr()
B的静态块总是能成功填充它的地图吗?我假设JVM能够处理这个。加载类时执行静态块的顺序是否存在任何问题,这反过来又不能保证B正确填充地图?我想确定,也许了解这背后的机制。
类A包含:
StringsMap块中的静态getStr(),它返回String从静态构建的
Strings类B包含:
MapMapusing的静态块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'。