Get hands-on training for JIRA Software, Confluence, and more at Atlassian Summit Europe. Register now ›

.magictrickcode pre {
overflow: auto;
}
.magictrickcode {
border-width: 1px;
border-style: dashed;
padding: 5px;
margin: 10px;
}

After reading a blog post about some of the quirks of the Java compiler and JVM, I thought I’d perform a magic trick for my colleagues to see how familiar they were with the same quirks.

The Trick

I have two hats and one ball. The ball looks like this:

Ball.java

public class Ball {
public static final String UNDER_HAT = "NONE";
}

The first hat looks like this:

HatOne.java

public class HatOne {
public boolean hasBall() {
return "ONE".equals(Ball.UNDER_HAT);
}
}

The second hat looks like this:

HatTwo.java

public class HatTwo {
public boolean hasBall() {
return "TWO".equals(Ball.UNDER_HAT);
}
}

The magic trick looks like this:

MagicTrick.java

public class MagicTrick {
public static void main(String... args) {
HatOne hatOne = new HatOne();
HatTwo hatTwo = new HatTwo();
if (hatOne.hasBall() && hatTwo.hasBall())
System.out.println("TADA!! The ball is under both hats!");
else if (hatOne.hasBall())
System.out.println("The ball is under hat one.");
else if (hatTwo.hasBall())
System.out.println("The ball is under hat two.");
else
System.out.println("Better luck next time.");
}
}

For this trick, I am not allowed to modify MagicTrick.java, HatOne.java or HatTwo.java, but I am allowed to change the implementation of Ball.java as much as I like. After making secret changes to Ball.java, I execute the magic trick:

$ java MagicTrick
TADA!! The ball is under both hats!

How did I do it?

The Solution

If you consider yourself a seasoned Java developer, I suggest you have a go at finding a solution before reading this section, it will be fun. I expected that a number of my colleagues would work out how I did it, but what I didn’t expect is that they would come up with 4 completely different ways of performing the trick.

Initially a solution was suggested that involved changing the package of some of the classes, but that meant editing the files, so that didn’t count. Then a really simple solution arose that I hadn’t thought of. It was suggested by Tom Davies, though with one small bug, which was fixed by Chris Mountford:

public class Ball {
static {
System.out.println("TADA!! The ball is under both hats!");
System.exit(0);
}
public static String UNDER_HAT = "NONE";
}

Well, that was too easy, so I changed the rules to say that the only class that was allowed to print any output was MagicTrick.java. Then came the solution that I was looking for, suggested by both Charles Miller and Chris Kiehl. It was:

  • Compile all classes
  • Modify Ball.java so UNDER_HAT=”ONE”
  • Compile Ball.java and HatOne.java
  • Modify Ball.java so UNDER_HAT=”TWO”
  • Compile Ball.java and HatTwo.java
  • Run MagicTrick – TADA!!

This solution exploits the way the Java compiler inlines static final fields wherever it can. The next solution, proposed by Chris Mountford, I thought someone might try. I don’t think a magician would be very wise though to use this solution, it is greatly dependent on the speed of the processor, the OS scheduler, and whatever else the system happens to be doing at the same time:

public class Ball {
public static String UNDER_HAT = foo();
static String foo() {
Thread changer = new Thread() {
public void run() {
UNDER_HAT= "TWO";
}
};
changer.start();
try {
Thread.sleep(94);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "ONE";
}
}

I thought that had to be all the solutions that would arise. But then, Matt Quail, a magician with a deep knowledge of the implementation of the String class and the way the JVM handles String literals, came up with this very elegant solution:

import java.lang.reflect.Field;
public class Ball {
public static Object UNDER_HAT;
static {
try {
new HatTwo().hasBall();
Field fValue = String.class.getDeclaredField("value");
fValue.setAccessible(true);
Field fOffset = String.class.getDeclaredField("offset");
fOffset.setAccessible(true);
Field fCount = String.class.getDeclaredField("count");
fCount.setAccessible(true);
String internedOne = "ONE";
String internedTwo = "TWO";
char[] none = {'N', 'O', 'N', 'E'};
UNDER_HAT = new String(none);
fValue.set(internedOne, none);
fOffset.setInt(internedOne, 0);
fCount.setInt(internedOne, 4);
fValue.set(internedTwo, none);
fOffset.setInt(internedTwo, 0);
fCount.setInt(internedTwo, 4);
} catch (Exception e) {
e.printStackTrace();
}
}
}

This solution exploits the way the JVM interns String literals, and changes the interned value of the String literals in the HatOne and HatTwo classes. Finally, I tried my hand at a solution that involved messing with class loaders:

import java.io.*;
public class Ball {
public static String UNDER_HAT = "ONE";
private static final String HAT_TWO = "cafebabe00000032000f0a0003000c07000d07000e0100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c6501000768617342616c6c01000328295a01000a536f7572636546696c6501000b48617454776f2e6a6176610c0004000501000648617454776f0100106a6176612f6c616e672f4f626a656374002100020003000000000002000100040005000100060000001d00010001000000052ab70001b100000001000700000006000100000001000100080009000100060000001a000100010000000204ac000000010007000000060001000000010001000a00000002000b";
static {
try {
MagicTrickClassLoader mtcl = new MagicTrickClassLoader();
Class magicTrickClass = mtcl.loadClass("MagicTrick");
magicTrickClass.getMethod("main", new Class[] { String[].class })
.invoke(null, new Object[] { new String[] {} });
System.exit(0);
} catch (Exception e) {
}
}
private static class MagicTrickClassLoader extends ClassLoader {
public Class loadClass(String name) throws ClassNotFoundException {
if ("MagicTrick".equals(name)) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
FileInputStream is = new FileInputStream(new File(
getClass().getResource(name + ".class").toURI()));
int b = is.read();
while (b >= 0) {
os..write(b);
b = is.read();
}
is.close();
byte[] bytes = os.toByteArray();
return super.defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
}
} else if (name.matches("HatTwo")) {
byte[] bytes = new byte[HAT_TWO.length() / 2];
for (int i = 0; i < HAT_TWO.length(); i += 2) {
bytes[i / 2] = (byte) Integer.parseInt(HAT_TWO.substring(i, i + 2), 16);
}
return super.defineClass(name, bytes, 0, bytes.length);
}
return super.loadClass(name);
}
}
}

Initially embedding Java byte code in a Java source file felt a bit hairy to me, so I implemented it using the javax.tools API, but that required creating temporary directories and the like, this solution ended up being simpler (if you count less lines of code as being simpler). So, have we exhausted all the ways to perform this magic trick?

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now