Community
Participate
Working Groups
Eclipse compiler has a bug and produces wrong bytecode for inner classes. The point is that reference to enclosing instance in constructor is assigned AFTER calling constructor of superclass. The result is null pointer exception when you overriding in the inner class a method called by constructor of superclass. Example: public class A { public int m; public void pp() { C c = new C(4); System.out.println(c.get()); } public static void main(String[] args) { A a = new A(); a.pp(); } class C extends B { public C(int x1) { super(x1); } protected void init(int x1) { x = m * x1; // <- NULL POINTER EXCEPTION because of m } } } class B { int x; public B(int x1) { init(x1); } protected void init(int x1) { x = x1; } public int get() { return x; } }
This is not a compiler bug, but rather a VM limitation since innerclasses have existed. The bytecode verification process enforces the first instruction inside a constructor to be a constructor invocation (super(...) or this(...)). Therefore, internals cannot be initialized for virtual calls which may occur indirectly through a super constructor invocation. This is a limitation in innerclass usage due to a VM constraint. Javac has the same behavior as we do, there is nothing we can do unfortunately, unless the VM specs was to change (which isn't the case).
It is not true that javac has the same behavior as you do actually. When you use "-source 1.4" option reference to enclosing instance is initialized BEFORE constructor of superclass is called. This is the difference. In 1.3: Method A. C(A,int) 0 aload_0 1 iload_2 2 invokespecial #1 <Method B(int)> 5 aload_0 6 aload_1 7 putfield #2 <Field A this$0> 10 return In 1.4: Method A. C(A,int) 0 aload_0 1 aload_1 2 putfield #1 <Field A this$0> 5 aload_0 6 iload_2 7 invokespecial #2 <Method B(int)> 10 return
You are right, this seems to have changed recently (-source 1.4). I even see the VM spec mentionning it ($4.8.2). Thanks for pointing this out, we will move accordingly for 1.4 source mode.
Actually, javac -target 1.4 is enough to trigger this behavior, note that pre1.4 vms would not accept such bytecodes.
Fixed in latest
The fact that <1.4 vms don't accept this bytecode doesn't mean that 1.4 compliant compiler shouldn't produce such bytecode. This is the way I undestand "1.4 compliant" in Eclipse - use only on >=1.4 vms.
This is only partially true, you may toggle the compiler for general 1.4 compliance, but still manually targeting a 1.1 VM (if you turn off assertions - source 1.3).
Verified.
*** Bug 290791 has been marked as a duplicate of this bug. ***