A constant expression is evaluated during compilation rather than at runtime. In Java, a primitive or String field initializer that is a compile-time constant expression is initialized during class loading, before ordinary class initialization begins. This timing difference can change the result of circular static initialization. section 3.9.3
A method call prevents early initialization
In a circular dependency, `static final String WELCOME = "Hello".toUpperCase()` is not a compile-time constant expression. If `B.MSG` reads `A.WELCOME` while A is still initializing, it can see `null`. Replacing that initializer with the literal `"Hello"` makes it available during class loading instead. section 3.9.3
class A {
private static final B unused = new B(); #1
static final String WELCOME = "Hello".toUpperCase();
public static void main(String[] args) {
System.out.println(B.MSG);
}
}
class B {
static final String MSG = A.WELCOME; #2
public static void main(String[] args) {
System.out.println(B.MSG);
}
}
The two classes isolate the ordering hazard: A creates B before assigning WELCOME, while B reads WELCOME during its own initialization. section 3.9.3
Compile-time evaluation also hides arithmetic operations from bytecode-based analysis. An overflowing integer constant expression is already reduced by compilation, so a tool such as SpotBugs cannot recover the original computation; IntelliJ IDEA can flag the source-level numeric overflow. section 4.2.1
Overflow computed before bytecode
`int microseconds = 24 * 60 * 60 * 1000 * 1000;` exceeds the `int` range, but the constant computation silently overflows. When variables participate, static analyzers are generally much less able to prove overflow. section 4.2.1
Treat compile-time constants as both an initialization and analysis boundary:
- Do not rely on a nonconstant static initializer being visible during circular class initialization; remove the cycle or make initialization order explicit. section 3.9.3
- Inspect integer literal calculations for range overflow, especially multiplication, rather than expecting bytecode analysis to catch them. section 4.2.1
- Keep format strings constant when possible, because static analysis can validate format arguments only when the format string is a constant. section 6.11
