在Java中,当我不在内部类中时,如何访问外部类?

问题描述 投票:32回答:8

如果我有一个内部类的实例,如何访问外部类从不在内部类中的代码?我知道在内部类中,我可以使用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; }
  }
}
java syntax nested
8个回答
32
投票

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();
    }
}

14
投票

没有办法,是设计使然。如果您需要通过内部实例的一个实例访问外部类,则您的设计是倒退的:内部类的要点通常仅在外部类中或通过接口使用。


8
投票

当您需要访问外部类时,添加getter有什么问题?这样,您可以控制是否允许访问。


6
投票

实际上,这是一个非常好的问题,例如,如果您需要能够检查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>接口,这将非常容易,即使在匿名类上,它也可以做到非常高效(无懈可击的内省处理!]


1
投票

如果您有一个(非静态的)内部类,那么按照定义,您将使用仅在外部类的封闭上下文内起作用的东西。因此,要获取内部类的句柄,您必须已经通过外部实例对其进行了检索。因此,我能看到的唯一需要访问器的方法是通过外部ref抢占内部,然后丢失或丢弃外部实例引用。


1
投票

这是您可能想要此行为的一个原因:您拥有内部类实例,需要使用反射来访问外部类中定义的方法。


1
投票

简单地写这个


0
投票

难道你不能做这样的事情:

© www.soinside.com 2019 - 2024. All rights reserved.