为什么扩展内部 class 的本地 class 不能访问内部 class 封闭实例?

Why can't a local class that extends an inner class access the inner class enclosing instance?

(我保留了 re-reading 这个问题的标题并考虑它看起来有多荒谬,但我向你保证这是对问题的最佳描述,我有一个实际的应用程序,这是最好的结构.我发誓我没疯。)

考虑以下问题。每个块都是一个单独的文件:

package myPackage;

public class A {

    public int i;

    public A(int i) {
        this.i = i;
    }

    public class B {

    }
}

package myPackage;

import myPackage.A.B;

public class Main {

    public static void main(String[] args) {
        class C extends B {
            public C(A enclosingInstance) {
                enclosingInstance.super();
            }

            public void show() {
                System.out.println(A.this.i);
            }
        }
        A myA = new A(2);
        C myC = new C(myA);
        myC.show();
    }
}

请注意,enclosingInstance 业务是解决涉及中间构造函数调用的问题。参见

我希望输出为“2”。但是相反,我在 System.out.println(A.this.i);:

上有一个编译错误

No enclosing instance of the type A is accessible in scope

我认为我试图解决的编程概念是合理的:在 main 中创建一个新类型的 B 以提供给 A,它使用 B 类型可以访问的 A 中的东西。

那么我做错了什么,或者为什么这在 java 中不可能?

EDIT/UPDATE:请注意,将 main 中的代码移至 non-static 方法时会出现相同的错误。也就是说,我尝试将 static void main 中的所有内容移动到 class Main 的一个新的 non-static 方法,称为 go()。然后我将 static void main 更改为单行 new Main().go();。错误在同一个地方。所以这似乎不是 class C 在静态上下文中定义的问题。

根据提供的信息,我会这样做:

public class B {
    protected A getOuterInstance() {
        return A.this;
    }
}

并让C继承并使用这个方法。我知道您不喜欢这种方法,但这是我能看到的最简单的答案。有了更多信息,我可能会提出一个尝试不涉及任何内部 class 的设计,因为这不是内部 classes.

的正常用例

这是你永远不应该为生产编写的荒谬代码。

Explicit Constructor Invocations

的文档中对此进行了部分解释

Qualified superclass constructor invocations begin with a Primary expression or an ExpressionName. They allow a subclass constructor to explicitly specify the newly created object's immediately enclosing instance with respect to the direct superclass (§8.1.3). This may be necessary when the superclass is an inner class.

所有这一切都表明 C 是局部 class (which is an inner class, which is kind of nonsense because if you declare it in a static method there is no enclosing instance),它是 B 的子 class 但不是嵌套 class 共 A。因此,没有封闭的实例。 C 的实例没有封闭实例。 (虽然如果你在实例方法中声明它会,但那将是 Main 的实例。)

新创建的对象的直接封闭实例(来自 JLS)是通过构造函数参数间接指定的。

你必须自己存储它

private A enclosingInstance;
public C(A enclosingInstance) throws CloneNotSupportedException {
    enclosingInstance.super();
    this.enclosingInstance = enclosingInstance;
}

并且由于A#ipublic,您可以正常访问它

public void show() {
    System.out.println(enclosingInstance.i);
}

您希望 A.this 引用 B 实例的封闭实例。但为什么要这样做呢?这不是语法的意思。 A.this 意味着 C 实例的封闭 A 实例,这没有意义,因为 C 不是 [=14= 的内部 class ].

为了更清楚地说明这一点,这里有一个示例,其中 C A 的内部 class。

public class A {

    public int i;

    public A(int i) {
        this.i = i;
    }

    public class B {
        void foo() {
            System.out.println(A.this.i);
        }
    }

    public class C extends B {
        C(A a) {
            a.super();
        }
        void bar() {
            System.out.println(A.this.i);
        }
    }

    public static void main(String[] args) {
        A a1 = new A(1);
        A a2 = new A(2);
        C c = a1.new C(a2);
        c.foo();
        c.bar();
    }
}

此处 C 扩展了 BCB 都是 A 的内部 class。因此任何 C 都有一个封闭的 A 实例,并且当被视为 B 时它也有一个封闭的 A 实例,并且 这些封闭实例是不同的(事实证明 foobar 打印不同的数字)。

所以,A.this 不可能是你想要的意思,因为它已经有别的意思了。我想语言设计者没有想出其他语法来表示超级 class 的封闭实例的原因是因为这样的语法会非常复杂,回报很少(已经存在简单的解决方法) .