在Java中,当我';我不在班里?

在Java中,当我';我不在班里?,java,syntax,nested,Java,Syntax,Nested,如果我有一个内部类的实例,如何从不在内部类中的代码访问外部类?我知道在内部类中,我可以使用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() metho

如果我有一个内部类的实例,如何从不在内部类中的代码访问外部类?我知道在内部类中,我可以使用
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; }
  }
}
public class Outer{ 
   public class Inner {
   }
}

public class UsesInner{
 Collection<Outer.Inner> c = new ArrayList<Outer.Inner>();
}

这不是故意的。如果您需要通过内部类的实例访问外部类,那么您的设计是向后的:内部类的点通常只在外部类中使用,或者通过接口。

外部$INTERNAR类的字节码将包含一个名为
的包范围字段,该字段的类型为
外部
。这就是非静态内部类在Java中的实现方式,因为在字节码级别没有内部类的概念

如果你真的想,你应该能够通过反射来读取这个字段。我从来没有任何必要这样做,所以最好是你改变设计,使它不需要

下面是使用反射时示例代码的外观。老兄,真难看


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

您就不能这样做吗:

public static class Inner { // static now
    private final Outer parent;

    public Inner(Outer parent) { this.parent = parent; }

    public Outer get Outer() { return parent; }
}
如果您有一个(非静态)内部类,那么根据定义,您正在处理一些只在外部类的封闭上下文中起作用的东西。因此,要获得内部类的句柄,必须通过外部实例检索它。因此,我能看到的唯一方法是,通过外部引用获取内部引用,然后丢失或丢弃外部实例引用

例如:

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; }
  }
}
public class Outer{ 
   public class Inner {
   }
}

public class UsesInner{
 Collection<Outer.Inner> c = new ArrayList<Outer.Inner>();
}
公共类外部{
公共阶级内部{
}
}
公众阶级的罪人{
集合c=新的ArrayList();
}

现在,填充c的唯一方法是创建Outer()实例。我很想看到这样的东西有什么有用的用途。

这里有一个原因,你可能想要这种行为:你有一个内部
实例,需要使用反射访问外部
中定义的方法


对于记录,
internal.getClass().getDeclaredField(“此$0”)
有效。由于该字段是
私有的
,您还需要调用
字段。setAccessible(true)
这实际上是一个很好的问题,例如,如果您需要能够检查
内部
类的两个不同实例是否共享
外部
类的相同实例(=或等于,具体取决于上下文)

我建议创建一个通用接口(对于命名的内部类不是绝对必需的,但可以是“instancedof”/casted to):

公共接口内部类{
外部getOuter();
}
可以应用于任何命名的内部类

然后你做一些类似的事情:

类MyInnerClass实现InnerClass{
外部getOuter(){
返回外部。这个;
}
//其余实施细节
}
通过这种方式,您可以从实现
InnerClass
接口的任何内部类访问外部类(并检查它是否实际实现了它)

如果您的内部类是匿名的,则只能执行以下操作(感谢Rich MacDonald提供的示例):

newinterfaceorabtractclass(){
Outer getOuter(){//效率非常低,但这是唯一的方法!
返回(外部)getClass().getDeclaredField(“此$0”);
}
/*其他方法*/
}
但是
InterfaceOrAbstractClass
必须实现
InnerClass
才能访问匿名类主体之外的
getOuter()

如果javac在所有内部类上自动实现某种
InnerClass
接口,那么就容易多了,即使在匿名类上,它也可以超级高效地实现这一点(没有缓慢的内省处理)

简单地写下这个

class Outer {
  class Inner {
    Outer outer = Outer.this;
  }
}

老实说,我也找不到好的理由。我只是在试图回答这个问题时偶然发现了它:在这种情况下,他想确保他有一个外部类的特定实例的内部类。我在另一个答案中建议他只在内部类中定义方法,这样就不会有问题了。不过,我还是很好奇是否有办法。你能解释一下你在解决什么问题吗?或者这是学术性的?主要是学术性的。我在回答这个问题时遇到了这个问题:我给出了两个答案,一个是按照OP的要求使用我上面使用的相同解决方法(getOuter()方法)。但在我的另一个答案中(已经被提升的答案),我说以不同的方式设计它,这样就没有必要了。但我仍然好奇是否有可能做到这一点。您提供的示例是这个问题的最佳答案。这也是我的想法,但我似乎找不到任何说明此限制的文档。如果你能找到任何官方的东西,我很乐意接受这个答案。这不是一个明确的“限制”-为什么要有关于缺少特定(相当模糊)功能的文档?15.8.3和15.8.4涵盖了它。“任何词汇封闭实例都可以通过显式限定关键字this来引用。”在这个问题中,它不是一个词汇封闭实例。从JNI(即通过
internal
类的
native
方法)访问它怎么样?这依赖于(IIRC)编译器,通常需要一个setAccessible。我认为(懒得查找规范)甚至该字段的命名都依赖于编译器,因此如果您尝试使用另一个编译器进行这种攻击,您可能会遇到问题。我正在阅读Java并发性的实践,其中一个示例演示了如果我们传递内部clas的实例,该引用如何通过内部类转义
new InterfaceOrAbstractClass<Outer>() {
    Outer getOuter() { // super inefficient but this is the only way !
        return (Outer)getClass().getDeclaredField("this$0");
    }
    /* other methods */
}
class Outer {
  class Inner {
    Outer outer = Outer.this;
  }
}