Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

On Using the Right Tool for the Job

DZone's Guide to

On Using the Right Tool for the Job

· Java Zone
Free Resource

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

Disclaimer: The code samples in the post below are for brain teasing only. Do not, I repeat, do not ever do such things for any other purpose!

A friend of mine is a big fan of puzzlers. Any puzzlers, including programming ones. Here’s his latest and greatest:

Write some code in the static initializer to make the assert pass:

public class Test {
 static {
//Write some code here
 }

public static void main(String[] args) {
 Integer a = 20;
 Integer b = 20;
 assert (a + b == 60);
 }
}

Don’t forget to enable assertions if you want to solve this one (-ea as VM parameter).

If you solved it, or don’t feel like puzzlers, read on for the solution and the punchline.

First, the solution: You need to know refection and two facts about Integers to solve this one:

  1. Integers have cache for all values in range -128 to 127.
  2. Integers use that cache during auto-boxing (as opposite to using Integer’s constructor, for example).

Well, you also need to know the exact implementation of the Integer class to figure out where the cache is and what’s the name, but rt.jar sources are here for the rescue. Guess what? the cache is a private variable inside a private inner class. Joy-joy.

Here’s the plan:

  1. Get Integer’s class object.
  2. Get the list of its inner classes.
  3. Find the right one (what a relief, it only has one. Or not – it is subject to change in future versions since we are digging in highly encapsulated stuff . Duh.)
  4. Get the cache field from it.
  5. It’s private, set it to accessible in order to get the value of the field.
  6. Change the value of “20″ to be “30″

Here’s the code of the static initializer:

 static {
try {
 Class<?>[] declaredClasses = Integer.class.getDeclaredClasses();
 Field cacheField = declaredClasses[0].getDeclaredField("cache");
 cacheField.setAccessible(true);
 ((Integer[]) cacheField.get(null))[20 + 128] = 30;
 } catch (Exception e) { e.printStackTrace(); }
 }

Personally, I hate it. It’s ugly, it messes with very low-level encapuslated stuff that one even doesn’t suppose to know, and it is fragile (e.g. it won’t work if Integer is created with constructor).

And fairly, we just got lucky. If Integers did not have the cache then we would not  have any way to change what “+” does!

So, why this simple trick is so difficult to impossible to implement? Simple – Java is not intended for those tricks. Java is static, and it is good! It means that you can rely on it. 20+20 will (almost always) be 40. That is Good.

If you want to do dynamic stuff, like changing the behavior of  a “+” operator, you’d better use the right tool for the job. E.g. – Groovy.

Here’s the Groovy version of the puzzler:

//Write some code here
Integer a = 20
Integer b = 20
assert 60 == a + b

Looks almost the same (without the main() mess, some ridiculous semicolons and the need to include -ea in VM parameters), but the difference in the way to achieve the desired is huge. Since Groovy is dynamic it is intended to do stuff like changing the behavior of the plus sign. Here’s the facts about Groovy that you need to know to solve this one:

  1. Groovy operates with wrappers, always.
  2. Groovy implements operators though methods. “+” is implemented in plus() method.
  3. Using Groovy’s MetaClasses you can easily replace method with any closure.

Here’s the plan:

  1. Get Integer’s MetaClass.
  2. Replace plus() method with implementation that returns 60.

That’s all. Really. Here’s the code:

Integer.metaClass.plus = {int i -> 60 }

Nuff said. Now you only have 2 options. Stop doing those ugly tricks, or at least do it with the right tools for the job.

 

 

 

 

 

 

 

 

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}