【问题标题】:What guarantees that this call to a static method from another class's static block works as expected?什么保证从另一个类的静态块调用静态方法按预期工作?
【发布时间】:2015-12-28 20:04:08
【问题描述】:

A 类包含:

  • 静态Strings
  • 一个静态 Map 填充在类的静态 阻止
  • 一个静态方法,比如getStr(),它返回一个从静态构建的String Strings

B 类包含:

  • 静态Map
  • 使用A.getStr() 填充Map 的静态块

B 的静态块总是会成功填充其地图吗?我假设JVM能够处理这个。加载类时静态块的执行顺序是否有任何问题,这反过来又不能保证B 正确填充地图?我想确定一下,也许了解这背后的机制。

【问题讨论】:

  • 为什么不能成功填充?更重要的是,为什么只有有时
  • 如果初始化中存在循环依赖,可能无法成功填充。
  • @mastov - 如果是这样,那么是否不能保证 B 将始终成功填充?
  • 哪里有循环依赖?我看到 B 依赖于 A,但不是相反,除非您的意思是说 A 的 Map 依赖于 B 的静态块(如果是,可以使用一些说明)。
  • 这里没有足够的信息来验证不存在循环依赖:我们没有类的实现及其所有依赖。所以,谨慎的回应是:不,它不会总是成功填充;它们可能不是这样的一个原因是周期性依赖。

标签: java static jvm static-methods static-block


【解决方案1】:

如果两个类在静态初始化期间具有循环依赖关系,事情就会变得棘手。 Java 确实有一个严格定义的初始化过程,并在检测到递归时退出。但是,这将取决于在运行时首先触发哪个类初始化。这意味着部分初始化的类可能是可见的(在您的情况下,看到一个空的 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'。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 2015-02-13
  • 2013-10-18
  • 1970-01-01
相关资源
最近更新 更多