...
While this statement typically holds, it can be misleading as it does not account for instances that use values of static final
fields initialized at a later stage. Even if a field is static final
, it is not necessarily initialized before being read.
Noncompliant Code Example (intra-class cycle)
Wiki Markup |
---|
In this noncompliant code example, a recursive attempt is being made to initialize the class, creating an initialization cycle. Because such recursive attempts are ignored by the JVM, the default value of {{deposit}} is {{0}} during the initialization \[[Bloch 2005|AA. Bibliography#Bloch 05]\]. The code tries to calculate the account balance by subtracting the processing fee from the deposited amount, but fails to do so. The {{Cycle}} class object {{c}} is instantiated before the {{deposit}} field gets initialized. |
...
As a result, the constructor Cycle()
is invoked which computes the balance based on the initial value of deposit
(0) rather than the random value. As a result, the balance always remains -10
.
Compliant Solution (intra-class cycle)
This compliant solution changes the initialization order of the class Cycle
so that the fields meant to be used in computations get duly initialized without creating any dependency cycles.
...
As initialization cycles can become insidious when many classes are involved, proper care must be taken to inspect the control flow.
Noncompliant Code Example
...
(inter-class cycle)
This noncompliant code example uses an inner class that extends the outer class. The outer class in turn, uses the {{static}} instance of the inner class. This results in a circular initialization issue \[[Findbugs 2008|AA. Bibliography#Findbugs 08]\].uses two classes with static variables that depend on each other. When seen together, the cycle is obvious, but the cycle can be easily missed when the classes are viewed separately.
Code Block | ||
---|---|---|
| ||
class A {
static public final int a = B.b + 1;
// ...
}
|
Code Block | ||
---|---|---|
| ||
public class CircularClassInitB { static class InnerClassSingletonstatic extends CircularClassInit { static public final InnerClassSingletonint singletonb = new InnerClassSingleton()A.a + 1; } static final CircularClassInit foo = InnerClassSingleton.singleton; } |
Compliant Solution
// ...
}
|
The values of A.a
and B.b
can vary, depending on which class gets initialized first. If class A
is initialized first, then A.a
will have the value 2 and B.b
will have the value 1. The values will be reversed if class B
is initialized first.
Compliant Solution (inter-class cycle)
This compliant solution eliminates one of the dependenciesThis compliant solution removes the instance of the inner class from the outer class.
Code Block | ||
---|---|---|
| ||
public class CircularClassInitA { static class InnerClassSingletonstatic extendspublic CircularClassInitfinal { int a = 2; static final InnerClassSingleton singleton = new InnerClassSingleton(); } } // ... } // class B unchanged: b = A.a + 1 |
With the cycle broken, the initial values will always be A.a = 2
and B.b = 3
, no matter which class gets initialized first Notably, class initialization cycles can also occur because of circularity in the code present within the {{static}} initializers of two or more classes \[[Findbugs 2008|AA. Bibliography#Findbugs 08]\]. Also see the related guideline [DCL13-J. Avoid cyclic dependencies between packages]. Wiki Markup
Risk Assessment
Initialization cycles may lead to unexpected results.
...