April’s fool — foolish Java games not for production

I’ve read an article in the German Javamagazin from Arno Haase and I think I’ll show you the foolish games of Java on the 1st of April.

The title of the article is “More or less final” and the main thought is about final variables in Java — and they are not as final as we might think. So I adapted some of the examples and I encourage you to think about the results of the following code snippet before reading on.

public static void main(String[] args) throws Exception
{
    String s1 = new StringBuilder("Welcome").toString();
    String s2 = s1.intern();

    System.out.println(s1 != "Welcome");
    System.out.println("Welcome".equals(s1));
    System.out.println(s2 == "Welcome");
    System.out.println("Welcome".equals(s2));
    magick();
    System.out.println("Welcome");
    System.out.println(s1);
    System.out.println(s2);

    System.out.println("-------------");

    integerTricks();
    System.out.println((Integer)5 * 3);
    System.out.println(Integer.valueOf(5));
}

Note: Do not use anything in a production code. Developers expect to have final variables that are really final and after some months you won’t remember why you created this reflection method — and what it really does.

OK, I admit without knowing what magick() and integerTricks() do is it less easy to figure out the results of the print statements. However, if you think about Java and the immutable variables (as String) and Integer behavior, the differences between “equals()” and “==” you’d think the result would be:

true
true
false
true
Welcome
Welcome
Welcome
-------------
15
5

Line 4 in the “main method” listing does something strange to get the “is the same object” operator (==) return true for s2. If you read the Javadoc you’ll see, that the String class maintains it’s own String pool and you’ll get the same object back for two Strings if they are equal.

The result of the example code is as follows (and not the same as expected):

true
true
true
true
Goodbye
Welcome
Goodbye
-------------
33
11

Yes, the two methods magick() and integerTricks() do something strange with the code.

String pool

private static void magick() throws Exception
{
    final Field field = String.class.getDeclaredField("value");
    field.setAccessible(true);
    field.set("Welcome", "Goodbye".toCharArray());
}

The magick() method alternates the array (or global pool) of strings which the JVM creates at load-time to save some memory. Strings, which are composed at runtime (i.e. with StringBuilders) will not be stored automatically in this pool. And the String.intern() method forces the String to this pool. As the magick() method operates on  the pool of Strings the StringBuilder-created String stays “Welcome” although the intern and the previously printed one gets “Goodbye”.

Integer cache

private static void integerTricks() throws ClassNotFoundException, Exception
{
    final Class cls = Class.forName("java.lang.Integer$IntegerCache");
    final Field field = cls.getDeclaredField("cache");
    field.setAccessible(true);
    final Integer[] cache = (Integer[])field.get(null);

    cache[133] = 11;
}

Integer objects have an internal cache too. This is maintained for a high-performace auto-boxing of ints into Integer objects. The default caching is from -128 to 127 enabled so the 133th element in this array is the number 5. Because we change the value of 5 to 11 every auto-boxing (as in the main method) and Integer.valueOf(5) results in an unexpected 11 — so (Integer) 5 * 3 yields 33 instead of 15.

Conclusion

The Java Reflection API allows modification of final fields too — so be careful with your final variables. They are not as final as you might think. So as in my note at the beginning: do not use this in a real application. The only meaningful scenario (I agree with Arno Haase) is de-serialization of objects. A generic code does not know which constructor to call with which values if it tries to reconstruct an object state from byteflow. But it can create an “empty” object and fill the fields via the Reflection API. And after the object is fully initialized the JLS guarantees the same visibility options as if the Object would have been created along the “normal way”.

And as always: the sources are found in my GitHub repository.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s