The Java static compiler (javac) inlines some static final variables and brings the values directly to the constant pool. Consider the following example. Class A defines some constants (public static final variables):
public class A {
public static final int INT_VALUE = 1000;
public static final String STRING_VALUE = "foo";
}
Class B uses these constants:
public class B {
public static void main(String[] args) {
int i = A.INT_VALUE;
System.out.println(i);
String s = A.STRING_VALUE;
System.out.println(s);
}
}
When you compile class B, javac gets the values of these constants from class A and inlines these values in B.class. As a result, the dependency B had to class A at the compile time is erased from the bytecode. This is a rather peculiar behavior because you are baking in the values of these constants at the time of compilation. And you would think that this is one of the easiest things that the JIT compiler can do at runtime.
Is there any way or any hidden compiler option that lets you disable this inlining behavior of javac? For the background, we're looking into doing bytecode analysis for dependency purposes, and it is one of the few cases where bytecode analysis fails to detect compile-time dependencies. Thanks!
Edit: this is a vexing issue because normally we don't control all the source (e.g. third-party libraries that define constants). We're interested in detecting these dependencies from the perspective of using the constants. Since the reference is erased from the code that uses the constants, there is no easy way to detect them, short of doing source code analysis.
To stop inlining you need to make the values non-compile time constants (the JLS term). You can do this without the use of functions and creating a minimum of bytecode by using a
null
in the initialiser expression.Although it is very literal in its code generation,
javac
should optimise this to be a push of an immediate integer followed by a store to the static field in the static initialiser.JLS 13.4.9 deals with this issue. Their recommendation is to basically avoid compile-time constants if the value is in any way likely to change.
Rewrite class A like: