从嵌套内部类中访问外部内部类

4

我有以下代码:

public class Bar {}
public class FooBar {}

public class Foo {

    public void method() {
        new Bar() {

            void otherMethod() { }

            void barMethod() {

                new FooBar() {

                    void fooBarMethod() {
                        Bar.this.otherMethod(); // not compiles
                    }   
                };
            }
        };
    }

}

我有一个匿名内部类,其中又有一个匿名内部类FooBar。问题是:如何从内部内部类FooBar访问外部内部类Bar的方法?


1
这是一个纯理论问题还是你打算实际操作? - Sotirios Delimanolis
这是一个理论问题。 :) - WonderCsabo
1
阅读这篇文章 - Sotirios Delimanolis
@MiserableVariable,@Tim B 我扩展了这个例子。抱歉,我以为“Bar”和“FooBar”是现有类型,并且可以在匿名类中进行扩展,但我想无论在这种情况下,“Bar”是接口、抽象类还是类都无关紧要。 - WonderCsabo
2个回答

6
您可以直接使用简单名称调用该方法:
void fooBarMethod() {
    otherMethod(); // compiles
}

一旦在new FooBar()匿名类中定义另一个名称为otherMethod()的方法,该操作将失败。

Bar.this 是行不通的,因为它是一个没有名字的匿名类,在编译时给出了名称。它将得到一个类似于 Foo$1 的名称。所以你不能像 Bar.this 这样做。


好的,我已经编写了源代码:

class Bar { }

class FooBar { }

public class Demo {

    public static void main() {
        new Demo().method();
    }

    public void method() {
        new Bar() {

            void otherMethod() { System.out.println("Hello"); }

            void barMethod() {

                new FooBar() {

                    void fooBarMethod() {
                        otherMethod(); // not compiles
                    }   
                }.fooBarMethod();
            }
        }.barMethod();
    }
}

生成的类文件如下所示:
Bar.class
FooBar.class
Demo.class

Demo$1.class    // For `new Bar()` anonymous class
Demo$1$1.class  // For `new FooBar()` anonymous class

现在,让我们直接转到new FooBar()匿名类的字节码。该类将被命名为- Demo$1$1。因此,运行javap命令,我得到以下输出:

class Demo$1$1 extends FooBar {
  final Demo$1 this$1;

  Demo$1$1(Demo$1);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$1:LDemo$1;
       5: aload_0
       6: invokespecial #2                  // Method FooBar."<init>":()V
       9: return

  void fooBarMethod();
    Code:
       0: aload_0
       1: getfield      #1                  // Field this$1:LDemo$1;
       4: invokevirtual #3                  // Method Demo$1.otherMethod:()V
       7: return
}

那个 final 字段是指向 new Bar() 实例的引用副本。因此,otherMethod()this$1 引用上被调用,它是指向 new Bar() 匿名内部类实例的引用。你只是想要这样做,但由于这是一个匿名内部类,你无法直接访问 this 引用。但那是隐含的。

更详细的分析:


otherMethod 方法被调用时所引用的是什么?基本上,它为什么能够工作? - Sotirios Delimanolis
https://dev59.com/DXRA5IYBdhLWcg3w9y50 - Sotirios Delimanolis
@SotiriosDelimanolis 请查看更新后的答案。该方法在 new Bar() 引用上被调用。 - Rohit Jain
有些编译器不允许你直接在源代码中引用它。 - Sotirios Delimanolis
@SotiriosDelimanolis 无论如何我们都不能直接使用它。Bar.this 是不可用的。但是引用是隐式的。 - Rohit Jain
显示剩余6条评论

0

如果你给它们命名,那么它们就不是匿名内部类了,它们只是内部类。如果你不给它们命名,那么你不能显式地调用它们,尽管如果没有名称冲突,你仍然可以调用它们。

不过你的代码完全无效,因为你创建了一个新的Bar,但从未定义过一个名为Bar的类。

忘掉你所说的“不编译”的那一行,第一个“new Bar()”根本就不会编译...


2
我认为很明显这只是一个简化的例子,可以假设BarFooBar是现有的非最终类。 - WonderCsabo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接