在Java中,每当创建一个内部类实例时,它都会与外部类的一个实例相关联。出于好奇,是否可以将内部类与另一个外部类实例关联起来呢?
是的,这是可能的,尽管对我来说听起来像一个非常糟糕的主意。这个想法是使用反射将否则为final
指针设置为外部实例(这并不保证成功)。
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!"
}
}
这里的关键部分是outerThis.setAccessible(true);
——一个SecurityManager可能会强制执行禁止此操作的策略。
public class Outer {
public class Inner {}
}
...
Outer o = new Outer();
Outer.Inner i = o.new Inner();
然而,如果没有使用 setAccessible(true)
,就不可能将内部类的现有实例与其他外部类实例关联起来,因为指向封闭实例的字段是 final
的:
javap Outer$Inner
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
final Outer this$0;
public Outer$Inner(Outer);
}
您可以使用反射来实现。
只需获取内部类的所有字段(getClass().getDeclaredFields()
),并查看哪个字段保存了父级,然后更改它(使用field.set(innerInstance, newParent)
)。在此之前,您应该将字段设置为可访问状态-setAccessible(true)
)。
由于该字段似乎是final
,您可以查看此文章以了解如何绕过它。
也就是说,您根本不需要这样做-这是一个双重丑陋的黑客行为,没有任何实际的收益。
this$0
,后面可能跟随多个$
(也可能一个也没有)。这是否已经被明确规定了呢? - polygenelubricantsthis$1
。真有趣! - polygenelubricants