Community
Participate
Working Groups
I get a problem with the compiled code, but I can't really figure out if it's a compiler bug or a 'feature' of java. The execution of the following code generates a NullPointerException in a method added by the compiler. public class Test { abstract class Super { public Super() { hop(); } abstract void hop(); } class Inner extends Super { public Inner() { super(); } public void hop() { System.out.println(fField); } } private Object fField; public static void main(String[] args) { Test3 test= new Test3("foo"); Inner inn= test.new Inner(); System.out.println("Test ..."); } public Test3(Object field) { fField= field; } } The exception stack trace : Exception in thread "main" java.lang.NullPointerException at Test3.access$0(Test3.java:23) at Test3$Inner.hop(Test3.java:19) at Test3$Super.<init>(Test3.java:6) at Test3$Inner.<init>(Test3.java:15) at Test3.main(Test3.java:27) The problem is : the constructor of Inner calls the constructor of Super which calls hop() on 'this' instance. By polymorphism, Inner#hop() is called. In Inner#hop(), we try to access to fField, which in a field of Test. For get the value of this field, the method access$0(..) is called. This method returns the enclosing instance of the given object, the field this$0 of the given object. But in this case, this field is not yet initialised. So the methode returns null. For get the value of fField, a getField instruction is executed on the return value. As the value is null, the VM throws an exception. The question is: does this code is correct, and the compiler should manages the case ? or is it a weakness in java ? I tried to get an answer from the java specs, but I didn't find any good information. In the java lang spec, at http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#229267, there is something about anonymous classes in constructors, but it's not really relevant. The VM spec says to look at http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html In this document, there is one note (end of the first bloc in http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc2.html) which says that some implementations delay the initialisation of this$0 after the call of the super constructor, so the problem can occurs. But I didn't find anything saying that the initialisation of this$0 can't be done before the execution of the super constructor. For info, javac from the Sun 1.4.1 sdk generates the same type of code and throws the same NPE.
This is a known limitation of innerclass emulations, due to the fact that most VMs forbide initializing synthetic slots (this$0) prior to performing super constructor calls. This is precisely the scenario you are running into. Newer VMs will no longer reject code where synthetics are initialized before the super call, therefore if you toggle our compiler in 1.4 compliant mode, it will produce bytecodes doing the proper generation. If toggling our compiler in 1.4 mode, you'll be able to run on 1.4 JREs and get: foo Test ...
Closing