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

时间:2015-10-09 00:42:47

标签: java scope inner-classes local-class

(我一直在重新阅读那个问题标题并思考它必须看起来有多荒谬,但我向你保证这是问题的最佳描述,而且我有一个实际应用,这是最好的结构。我发誓我“我不疯狂。”

请考虑以下事项。每个块都是一个单独的文件:

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业务是解决涉及中间构造函数调用的问题。请参阅"Why can't outer classes extend inner classes?"

我希望输出为“2”。但相反,我在System.out.println(A.this.i);上有编译错误:

  

在范围

中无法访问类型A的封闭实例

我认为我试图解决的程序化概念是合理的:在main内创建一种新类型的B,以便给A使用A类中可以访问的东西。

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

编辑/更新:请注意,当main中的代码移动到非静态方法时,会出现相同的错误。也就是说,我尝试将static void main内的所有内容移动到名为class Main的{​​{1}}新的非静态方法。然后我将go()更改为单行static void main。错误在同一位置。因此,在静态上下文中定义new Main().go();似乎不是问题。

3 个答案:

答案 0 :(得分:3)

这是一个荒谬的代码,你永远不应该为生产而写。

部分地在Explicit Constructor Invocations

的文档中进行了解释
  

合格的超类构造函数调用以.75开头   表达式或Primary。它们允许子类构造函数   显式指定新创建的对象立即封闭   关于直接超类的实例(第8.1.3节)。 这可能是   当超类是内部类时必需。

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

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

您必须自己存储

Main

由于private A enclosingInstance; public C(A enclosingInstance) throws CloneNotSupportedException { enclosingInstance.super(); this.enclosingInstance = enclosingInstance; } A#i,您可以正常访问

public

答案 1 :(得分:3)

您希望A.this引用B实例的封闭实例。但为什么要呢?这不是语法的意思。 A.this表示A实例的封闭C实例,这没有意义,因为C不是A的内部类。

为了更清楚,以下是C A的内部类的示例。

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的内部类。因此,任何C都有一个封闭的A实例,当它被视为A时它还有一个封闭的B实例,并且这些封闭的实例是不同的(正如foobar打印不同的数字所证明的那样)。

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

答案 2 :(得分:1)

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

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

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