This is my first tech blog. I had sent this blurb to JavaWorld's Tips 'N Tricks, but got rejected. So, here it is:
Compiler optimizations may not always be welcome, especially if you are working with Constants.
SUMMARY:
Referring to Constants (public static final) contained in other classes can cause issues if you are not careful while building your code.
If you are using constants i.e. public static final references in your code, you must be aware of the fact that the Java compiler optimizes your code by replacing the references with the constants' values. This is done to improve performance. However, there are instances where this behaviour of the compiler can cause strange errors to occur. For example, consider this code snippet:
package def;
import abc.TestConstantA;
//other imports...
public class TestConstantB
{
...
System.out.println("TestConstantA : " + abc.TestConstantA.CONSTANT_A);
System.out.println("TestConstantA : " + abc.TestConstantA.CONSTANT_A1);
...
}
The class in package
def
imports the class TestConstantA
from the package abc
and uses the TestConstantA.CONSTANT_A
variable. On compiling the two packages, we can decompile the class files by using a Decompiler such as DJ. Doing so, reveals the optimization made by the compiler:
//Decompiled code
package def;
//other imports...
public class TestConstantB
{
...
System.out.println("TestConstantA : 1010");
System.out.println("TestConstantA : Hello_World");
...
}
The Constants have been replaced with their actual values. Even the
import abc.TestConstantA;
statement has been removed.Next, comes the interesting part! Change the values of
abc.TestConstantA.CONSTANT_A
and abc.TestConstantA.CONSTANT_A1
to new values and compile only the abc
package. You will realize, to your horror that the def.TestConstantB
, which we did not recompile with the new abc
code, still uses the old abc.TestConstantA
values hard-coded! This can happen to you especially if you are using Third-party libraries and when you are not careful with your build process.Constant substitution during compilation is not as bad as I have made it look like. You can use it to do Conditional compilation like so:
private static final boolean DEBUG = false;
...
if(DEBUG)
{
System.out.println("Debug message. Works only if DEBUG is true");
}
Decompiling the class shows that the
if
block is absent from the class. This is because the DEBUG
evaluates to false
and a second optimization knocks off this unreachable if(false){...}
block. This reduces unnecessary variable checks and also reduces the bytecode size.RESOURCES:
Source code:
Should you call a frequently accessed constant directly? : http://www.javaworld.com/javaworld/javaqa/2001-07/03-qa-0720-direct.html
DJ Decompiler: http://members.fortunecity.com/neshkov/dj.html
0 comments:
Post a Comment