Java inner classes and inheritance: is there a duplicate xref?
Consider this scenario with inner classes and inheritance:
class X{
class A{
X foo(){
return X.this; // outer this reference to X returned
}
}
}
class Y extends X{
class B extends A {
Y foo(){
return Y.this; // outer this reference to Y returned
}
}
}
What does the layout of the class look like B
? Does it have two xrefs this
that point to the same object? Or it only has one external link this
. What is the type of this link?
The reason I'm asking is: I have a more or less deep hierarchy that uses nested classes. If the xref has this
been replicated for each inheritance level, then I should think about this construct.
Also, I'm just curious about this design detail of the Java programming language.
I used javap
to check the layout: the pointer is this
indeed replicated
class X$A {
final X this$0; // <-- first reference
X$A(X);
X foo();
}
class Y$B extends X$A {
final Y this$0; // <-- second reference
Y$B(Y);
Y foo();
X foo();
}
source to share
You can use javap
to find out what fields a class has. (This depends on the compiler, not the JVM.) In this case:
C:\Users\Jon\Test>javap -p Y$B
Compiled from "Test.java"
class Y$B extends X$A {
final Y this$0;
Y$B(Y);
Y foo();
X foo();
}
So, as you can see, one link to the enclosing instance Y
is - but X$A
will also contain a link to the attached instance X
(which you can check with javap -p X$A
if you like). So yes, the object will have two fields to include instances.
You can use javap -c Y$B
to view the body of the constructor, which shows that the attached instance of the instance is Y
then passed to the constructor X.A
as an instance reference X
, confirming that the two fields will have the same value.
However, I have not yet discovered where in the JLS this is addressed. This in itself is a concern - if you're in a situation that is difficult to explain with the JLS, it's a pretty good hint that other developers won't be able to keep track of what's going on. This seems like a confusing design to me ... if you don't really need all these nested classes, I would try to avoid them.
source to share
I think that every inner class in the inheritance hierarchy has its own "outer this" reference, because B can have a constructor like
public B(X a) {
a.super();
}
So you can do
X x = new X();
Y y = new Y();
Y.B b = y.new B(x);
You now have an instance of YB, where the foo () method returns y, but the original foo method returns x!
source to share