java.lang.ClassCircularityError:<类名>
java.lang.ClassCircularityError: <class name>
ID: java/class-circularity-error
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| Java 8 | active | — | — | — |
| Java 11 | active | — | — | — |
| Java 17 | active | — | — | — |
| Java 21 | active | — | — | — |
根因分析
JVM在类初始化期间检测到循环依赖,其中类A的静态初始化器触发了类B的加载,而类B又触发了类A的加载,此时A的初始化尚未完成,导致JVM无法解决的无限循环。
English
The JVM detected a circular dependency during class initialization, where class A's static initializer triggers loading of class B, which in turn triggers loading of class A again before A's initialization is complete, causing an infinite loop that the JVM cannot resolve.
官方文档
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ClassCircularityError.html解决方案
-
Refactor the circular dependency by moving shared static fields or methods to a third utility class. For example, if class A uses `B.CONSTANT` and class B uses `A.CONSTANT`, create a `Constants` class: `public class Constants { public static final int VALUE = 42; }` and have both A and B reference it. -
Use lazy initialization for static fields that cause the cycle. Replace `public static final Foo foo = new Foo();` with a holder class pattern: `private static class Holder { static final Foo foo = new Foo(); }` and access it via `Holder.foo`. This defers loading until the field is actually accessed. -
If using a dependency injection framework like Spring, ensure beans are not involved in circular references. Use `@Lazy` annotation on one of the beans: `@Lazy @Component public class A { ... }` to break the initialization cycle.
无效尝试
常见但无效的做法:
-
Remove static initializers entirely from the affected classes
75% 失败
Static initializers often hold essential configuration or resource loading. Removing them may break the application's functionality. The circular dependency should be resolved by refactoring, not by elimination.
-
Add Thread.sleep() in static initializers to break the cycle
95% 失败
Sleeping does not break the circular dependency; it only delays the crash. The JVM will still detect the cycle when the other class is loaded, and the error will occur after the sleep.