• Post Reply Bookmark Topic Watch Topic
  • New Topic

Inner class strange behavior  RSS feed

 
Sun LiWei
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


Output:
new Outer$Inner1:
foo=Outer.foo
bar=Inner1.bar
new Outer$Inner2:
foo=null
java.lang.NullPointerException
at Outer.access$100(JavaTest.java:1)
at Outer$Inner2.getBar(JavaTest.java:37)
at Outer$Inner1.<init>(JavaTest.java:14)
at Outer$Inner2.<init>(JavaTest.java:29)
at Outer.<init>(JavaTest.java:6)
at Outer.main(JavaTest.java:43)


I can't explain the null situation here.


why NullPointerExceptin is thrown??? why foo is null in Inner2 class?what is the initiating order of a java class ??
 
Vlado Zajac
Ranch Hand
Posts: 245
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Constructor of Inner2 calls constructor of Inner1 before initialization of
Inner2.foo so when the Inner1 constructor calls getFoo (from Inner2) it
returns null.

The NullPointerException is thrown because Inner2's hidden reference to
Outer is also initialized after Inner1 constructor so getBar (from Inner2)
calls null.access$100() (the hidded reference is null). I believe that this hidden method is used to retrieve value of bar from Outer class.
 
Vlado Zajac
Ranch Hand
Posts: 245
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In Outer foo and bar are private so to access them from inner classes
the compiler creates special methods access$000 and access$100.
 
marc weber
Sheriff
Posts: 11343
Java Mac Safari
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I agree with Vlado...

When you attempt to create an instance of Inner2 (which extends Inner1), the constructor of Inner1 is called before instance variables of Inner2 are initialized. Within the Inner1 constructor, getFoo() is called. This is invoking the overridden method in Inner2 (which you'll see if you add a println to the method), which is trying to access the foo variable in Inner2, which is not yet initialized. That explains the null.

If you comment out the bar declaration in Inner1, you will see that Outer.bar has been initialized before the exception is thrown. However, making Outer.bar static allows the program to run. Therefore, it makes sense that Inner2 simply does not yet have its reference to Outer (which it needs regardless of whether Outer.bar is private).
 
Sun LiWei
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So,is the initiating order of a inner class is

1)super()
3)the hidden reference to the outter class(maybe here)
2)instance variable(s)
3)the hidden reference to the outter class(also maybe here)
4)it's own constructor

This hidden reference is the thing i don't know before.when exactly this reference is initialized?
 
marc weber
Sheriff
Posts: 11343
Java Mac Safari
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, this is a tangled web of partially constructed objects and polymorphism among inner classes. But I believe the outer reference is available to the extended inner class when super() returns.

In my test code below, I've commented the NullPointerExceptions. Here's what I think is happening...

We're trying to make an Outside object. In the process of initializing the members, we try to make an instance of an inner class that extends another inner class. So the constructor of the extended class implicitly calls the constructor of its parent class. Within the constructor of that parent class, a method is called (via polymorphism) in the not-yet-constructed extended class. And that method attempts to reference a variable of the outer class. This is where the problem occurs (regardless of whether that variable is private). However, if we simply comment out the polymorphic method call in the inner parent constructor and allow the extended constructor's super() to return, then we're okay. The constructor of the extended class is then able to access the variable in the outer class.


NOTE: I was only able to do this with inner class constructors calling polymorphic methods that reference outer class variables. I was unable to reproduce the problem in a simpler context.
[ September 11, 2004: Message edited by: marc weber ]
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!