Skip to main content

The solution

You might expect it to print out 104, "10" being the sum of the fields and then "4" being the number of fields. You would of course be wrong :-)

If you run the following code you won't get a number out at all, you'll get an exception:


Exception in thread "main" java.lang.IllegalArgumentException: Attempt to get test.Outer field "test.Outer$Inner.this$0" with illegal data type conversion to int
at sun.reflect.UnsafeFieldAccessorImpl.newGetIllegalArgumentException(UnsafeFieldAccessorImpl.java:46)
at sun.reflect.UnsafeFieldAccessorImpl.newGetIntIllegalArgumentException(UnsafeFieldAccessorImpl.java:111)
at sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.getInt(UnsafeQualifiedObjectFieldAccessorImpl.java:41)
at java.lang.reflect.Field.getInt(Field.java:499)
at test.Outer.(Outer.java:21)
at test.Outer.main(Outer.java:29)


The key here is actually down to an implementation detail of Java - specifically how inner classes have a reference to their outer classes. If we make the inner class static (static inner classes don't have a reference to their enclosing class) then the problem goes away and we get the expected output, 104. So what's happening here?

It might help to think how a non-static inner class can always access its outer class. And it also might help if I tell you it's more along the realms of hackery than black magic! The key here is a field, this$0, that the compiler puts in every inner class. This is set by a constructor the compiler also puts in the inner class which is called when an object of this type is instantiated. It's an implementation detail, but quite a geeky and fun one to play around with. If you decompile the class files, you can actually see this extra field and constructor in plain daylight.

I got the idea for this puzzle from http://www.javaspecialists.eu/archive/Issue062.html - this explains this implementation detail far more accurately if you want to take a look.

So, we've got an extra field in the class that's of type Outer, not int. So when we try to call getInt() on this field, we understandably get an error.

As a follow on puzzle which you should now be able to answer, if we change this line:

catch(IllegalAccessException ex) {}

to:
catch(Exception ex) {}


what's printed out now?


The answer? 105. The values that are ints are still summed, so we get 10, but there's still 5 fields in the Inner class!

This is quite frankly a shoddy way to do things anyway, and the chances of doing something like this in real life are rather remote. But how could we fix it? One option is to check for synthetic fields and ignore them - synthetic fields are ones generated by the compiler and not by the user. So if we put if(field.isSynthetic()) continue; as the first line in the for loop and check for similar synthetic fields in counting them at the end, the problem goes away. There's a catch though - there's no requirement for the compiler to actually mark anything as synthetic. It's a bit like using a well established class in the sun package - while it might help in situations like this and is likely to be fine, it shouldn't really be relied upon.

This may seem like a silly example, but it does serve a few lessons. First, as shown by the follow on puzzle, if you just catch all exception types and expect everything to work, you may well get caught out by bugs you weren't expecting, but can really bite you later. Secondly, don't use reflection to loop through fields. It's just plain wrong. If you really have to, at least check for synthetic fields and make sure the fields are of the type you expect. And lastly, decompiling compiled code and looking at the results can be rather interesting in uncovering some Java implementation details!

Comments

Popular posts from this blog

The comprehensive (and free) DVD / Blu-ray ripping Guide!

Note: If you've read this guide already (or when you've read it) then going through all of it each time you want to rip something can be a bit of a pain, especially when you just need your memory jogging on one particular section. Because of that, I've put together a quick "cheat sheet" here which acts as a handy reference just to jog your memory on each key step.

I've seen a few guides around on ripping DVDs, but fewer for Blu-rays, and many miss what I believe are important steps (such as ensuring the correct foreign language subtitles are preserved!) While ripping your entire DVD collection would have seemed insane due to storage requirements even a few years ago, these days it can make perfect sense.

This guide doesn't show you a one click approach that does all the work for you, it's much more of a manual process. But the benefits of putting a bit more effort in really do pay off - you get to use entirely free tools with no demo versions, it's …

Expanding JavaFX's media support

Note: For those that don't want to read through the post and just want the patch for MKV support, you can grab it from this ticket, or here if you don't have a JIRA account.
Background One of the predominant things lacking a "nice" approach in the Java world for years now has been good media support. Oh sure, we had JMF, but anyone who ever had the misfortune of using that will I'm sure understand why that never really took on. (Yes, it really was that bad.) A few other approaches came and went, most notably Java Media Components - but none ever made there way into core Java, and for a long time it became pretty de-facto knowledge that if you wanted any form of comprehensive media support in Java, you used a cross-platform native library, perhaps with a Java wrapper.

However, when JavaFX 2 came along we were provided with a new, baked in media framework that provided this functionality on the Java level! This is a massive step forward, sure it uses GStreamer unde…

Draggable and detachable tabs in JavaFX 2

JavaFX currently doesn't have the built in ability to change the order of tabs by dragging them, neither does it have the ability to detach tabs into separate windows (like a lot of browsers do these days.) There is a general issue for improving TabPanes filed here, so if you'd like to see this sort of behaviour added in the main JavaFX libraries then go ahead and cast your vote, it would be a very welcome addition!

However, as nice as this would be in the future, it's not here at the moment and it looks highly unlikely it'll be here for Java 8 either. I've seen a few brief attempts at reordering tabs in JavaFX, but very few examples on dragging them and nothing to do with detaching / reattaching them from the pane.

Given this, I've decided to create a reusable class that should hopefully be as easy as possible to integrate into existing applciations - it extends from Tab, and for the most part you create it and use it like a normal tab (you can just add it to…