如果我有一个内部类的实例,如何访问外部类从不在内部类中的代码?我知道在内部类中,我可以使用Outer.this
来获取外部类,但找不到任何外部方法来获取此类。
例如:
public class Outer {
public static void foo(Inner inner) {
//Question: How could I write the following line without
// having to create the getOuter() method?
System.out.println("The outer class is: " + inner.getOuter());
}
public class Inner {
public Outer getOuter() { return Outer.this; }
}
}
Outer$Inner
类的字节码将包含类型为this$0
的包范围字段Outer
。这就是用Java实现非静态内部类的方式,因为在字节码级别上没有内部类的概念。
如果您确实愿意,您应该能够使用反射阅读该字段。我从来不需要这样做,因此最好更改设计以使其不再需要。
这是使用反射时示例代码的外观。天哪,这很丑。 ;)
public class Outer {
public static void foo(Inner inner) {
try {
Field this$0 = inner.getClass().getDeclaredField("this$0");
Outer outer = (Outer) this$0.get(inner);
System.out.println("The outer class is: " + outer);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public class Inner {
}
public void callFoo() {
// The constructor of Inner must be called in
// non-static context, inside Outer.
foo(new Inner());
}
public static void main(String[] args) {
new Outer().callFoo();
}
}
没有办法,是设计使然。如果您需要通过内部实例的一个实例访问外部类,则您的设计是倒退的:内部类的要点通常仅在外部类中或通过接口使用。
当您需要访问外部类时,添加getter有什么问题?这样,您可以控制是否允许访问。
实际上,这是一个非常好的问题,例如,如果您需要能够检查Innner
类的两个不同实例是否共享同一Outer
类的实例(==或等于,取决于上下文)。
我建议创建一个通用接口(命名内部类不是绝对必需的,但可以“实例化” /广播到):
public interface InnerClass<Outer> {
Outer getOuter();
}
可以应用于任何命名的内部类。
然后您执行类似的操作:
class MyInnerClass implements InnerClass<Outer> {
Outer getOuter() {
return Outer.this;
}
// remaining implementation details
}
这样,您可以从任何实现InnerClass<Outer>
接口的内部类中访问外部类(并检查它是否实际实现了它。)>
[如果您的内部类是匿名的,则只能这样做(感谢Rich MacDonald提供的示例):
实现new InterfaceOrAbstractClass<Outer>() { Outer getOuter() { // super inefficient but this is the only way ! return (Outer)getClass().getDeclaredField("this$0"); } /* other methods */ }
但是
InterfaceOrAbstractClass
必须
InnerClass<Outer>
以便能够在匿名类主体之外访问getOuter()
!如果javac在所有内部类上自动实现某种InnerClass<Outer>
接口,这将非常容易,即使在匿名类上,它也可以做到非常高效(无懈可击的内省处理!]
如果您有一个(非静态的)内部类,那么按照定义,您将使用仅在外部类的封闭上下文内起作用的东西。因此,要获取内部类的句柄,您必须已经通过外部实例对其进行了检索。因此,我能看到的唯一需要访问器的方法是通过外部ref抢占内部,然后丢失或丢弃外部实例引用。
这是您可能想要此行为的一个原因:您拥有内部类实例,需要使用反射来访问外部类中定义的方法。
简单地写这个
难道你不能做这样的事情: