Possible to change the outer class instance of an inner class in Java?
In Java, whenever an inner class instance is created, it is associated with an instance of an开发者_StackOverflow中文版 outer class. Out of curiosity, is it possible to associate the inner class with another instance of an outer class instead?
Yes, this is possible, although it sounds like a really bad idea to me. The idea is to set the otherwise final
pointer to the outer instance using reflection (which is not guaranteed to succeed).
import java.lang.reflect.*;
public class Me {
final String name;
Me(String name) {
this.name = name;
}
class InnerMe {
String whoAreYou() {
return name;
}
}
InnerMe innerSelf() {
return new InnerMe();
}
public static void main(String args[]) throws Exception {
final Me me = new Me("Just the old me!");
final InnerMe innerMe = me.innerSelf();
System.out.println(innerMe.whoAreYou()); // "Just the old me!"
Field outerThis = innerMe.getClass().getDeclaredFields()[0];
outerThis.setAccessible(true);
outerThis.set(innerMe, new Me("New and improved me!"));
System.out.println(innerMe.whoAreYou()); // "New and improved me!"
}
}
The crucial part here is outerThis.setAccessible(true);
-- a SecurityManager could enforce a policy that prohibits this from succeeding.
If you are speaking about instantiation time, it's possible using the following syntax:
public class Outer {
public class Inner {}
}
...
Outer o = new Outer();
Outer.Inner i = o.new Inner();
However, it's not possible (without setAccessible(true)
) to associate the existing instance of inner class with the other instance of outer class, because the field pointing to the enclosing instance is final
:
javap Outer$Inner
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
final Outer this$0;
public Outer$Inner(Outer);
}
You should be able to, using reflection.
Just get all fields of the inner class (getClass().getDeclaredFields()
)and see which field holds the parent, then change it (using field.set(innerInstance, newParent)
. Before that you should make the field accessible - setAccessible(true)
)
Since the field appears to be final
, you may take a look at this article to see how to circumvent that.
That said, you shouldn't need to do this at all - it would be a double ugly hack for no actual gain.
精彩评论