Constant Value in Java Class Binary
To do unit test or regression, we create a delta sandbox from base level code, and then upload the java source modified to the build machine, and run ant to build it.It would only compile the modified java sources and build a jar with other old class files.
Today I find an interesting and weird thing.
I change the constant value in one source class. During my unit test, I find that in other classes, which I don't change, and are not recompiled, it still uses old value of the constant. This is weird.
I am wondering this may be because java class byte-code hard-codes the constant value in the class file for efficiency or other reasons.
So I write a small program to verify it.
A class that defines the constant:
public class Constants
{
public static final int CONSTANT = 12345678;
}
A class - ConstantsReader that uses the constant:
public class ConstantsReader
{
public static int getConstant()
{
return Constants.CONSTANT;
}
}
A class - Main that prints out the value of the constant seen in ConstantsReader class.
public class Main
{
public static void main(String[] args)
{
System.err.println("Constants.CONSTAN: " + ConstantsReader.getConstant());
}
}
The copy these classes to another folder, and run Main class, it prints out:
Constants.CONSTAN: 12345678
Later, I change the constant value to 87654321, and copy the modified class ConstantsReader to the folder. Run Main class, we can see that it still prints old value:
Constants.CONSTAN: 12345678
Then I use Beyond Compare to compare the old class file of ConstantsReader and with the new one in Eclipse in Hex Viewer.
We can see that the constant value Constants.CONSTANT is replaced with literal constant value, ‘12345678’ in old version, ‘87654321’ in new version.
Use ‘javap -verbose -c -private ConstantsReader’ to compre the old and new version of the binary class.
Old version:
const #22 = String #23; // Constants.CONSTAN: 12345678
const #23 = Asciz Constants.CONSTAN: 12345678;
const #30 = int 12345678;
public static int getConstant();
Code:
Stack=2, Locals=0, Args_size=0
0: getstatic #16; //Field java/lang/System.err:Ljava/io/PrintStream;
3: ldc #22; //String Constants.CONSTAN: 12345678
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //int 12345678
10: ireturn
LineNumberTable:
line 5: 0
line 6: 8
New version:
const #22 = String #23; // Constants.CONSTAN: 87654321
const #23 = Asciz Constants.CONSTAN: 87654321;
public static int getConstant();
Code:
Stack=2, Locals=0, Args_size=0
0: getstatic #16; //Field java/lang/System.err:Ljava/io/PrintStream;
3: ldc #22; //String Constants.CONSTAN: 87654321
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //int 87654321
10: ireturn
LineNumberTable:
line 5: 0
line 6: 8
So my guess is verified, and it’s fun to know this truth.