If i have this code:
public class MySuperClass {
public String superString = "hello";
public MyChildClass makeChild() {
return new MyChildClass();
}
public class MyChildClass {
public String childString = "hi";
}
}
How can i get the MySuperClass instance from the MyChildClass instance?
Because i have this error:
There are VERY similar questions around stackoverflow, but this isn't a duplicate of any of them. What is the mistake in my code? How can i achieve what i said above, without making a method in the nested class which returns MySuperClass.this ? Imagine i do not own the code of MySuperClass...
I think this can be done because in the MyChildClass i can access the super instance with MySuperClass.this
, how can i get the MySuperClass instance attached to the child, from outside of the child class?
EDIT: i know casting is not the way to achieve this, it was an attempt to achieve what i wanted
You're mixing terms. "Child class" is pretty much always used for this relationship:
public class Parent {}
public class Child extends Parent {}
(And 'Parent' here, is termed the 'superclass' of Child).
In that context, 'how can I get my superclass from my child class' makes no sense. Child is an extension of Parent, when you write new Child()
there is just one instance, and that one instance is a combination of the stuff in Child and in Parent. It's not 2 separate things.
What you're talking about are inner classes. This relationship:
public class Outer {
public class Inner {}
}
Inner/Outer, vs. Child/Parent or Sub/Super.
So, what you actually ask is: How do I get the outer class instance?
That is not possible. It is an implementation detail of Inner, and it is up to Inner to expose this. If it doesn't want to, you don't get to access it.
But there are hacks and workarounds.
Inner
itself can do itWithin the {} that go with class Inner {}
you can do it:
class Outer {
class Inner {
public Outer getOuterInstance() {
return Outer.this;
}
}
}
At the class/JVM level, inner/outer classes don't exist. They're all just classes. That's why, if you compile the above, you end up with 2 class files, not one: Outer.class
as well as Outer$Inner.class
. The outer instance that Inner has is represented by a field.
This field is generally called this$0
, and is package private. So, something like:
Field f = Inner.class.getDeclaredField("this$0");
f.setAccessible(true);
Outer outer = (Outer) f.get(instanceOfInner);
But, in case the reflection code didn't already spell this out for you: Don't. This is horrible idea. A SecurityManager can stop you. The code is hard to read, this$0
doesn't make sense unless you riddle this with comments explaining what you're doing. Most of all, like any reflection, this is flat out not something the author of Outer/Inner intended for you to do, and whatever you use Outer for may simply not 'work' properly in some minor point release down the road, because you're not using this library in its intended fashion, therefore any support offered for it is lost. You pave your own road, which is bad, because you have no idea what the author truly intended, and you now effectively have to say that your libraries must never be updated without extensive testing, and not updating is a great formula to get yourself hacked. It's a bad idea in so many ways.
Also, the significantly reduced care for backwards compatibility as expressed by the current OpenJDK team (see project jigsaw which was the most breaking release of java in a good long while, how OpenJDK team almost decided to get rid of the SecurityManager within a single version jump until called back by the community, aggressive expansion of mostly pointless 'opens' checks, and more) - means that if you rely on this, don't be surprised if java18 or what not breaks your ability to do this, permanently.
So, do NOT do this.
The idea that the inner class actually has an invisible field of type outer is annoying and surprising. It stops garbage collection. It confuses your average java programmer because 'using' this java feature the way it was intended is very rare.
I therefore strongly suggest you always make your inner classes static
, and if you really want an instance of Outer
, make it explicit: Make Inner
static, then give it a private final Outer outer;
field.
It's equally efficient, it's very slightly more typing, but it is a lot more readable.