首页 > 解决方案 > “范围内没有 file1 类型的封闭实例”内部类错误

问题描述

我有一些代码(本质上它导入了这个其他类,它有一个我试图访问的内部类),但它带来了这个错误:

file2.java:5: error: no enclosing instance of type file1 is in scope
    public static class file3 extends file2.Inner {

“范围内没有 file1 类型的封闭实例”是什么意思?

这是代码:

package test;
import secret.file1;

public class file2 extends file1 {
    public static class file3 extends file2.Inner {
        public static void main(String[] args) {
            file3 outer = new file3();
            System.out.println(outer.x);
        }
    }
}

file1的代码:

package secret;

public class file1 {
    protected class Inner {
        public int x = 8;
    }
}

标签: javainheritanceinner-classes

解决方案


仅用于教育目的,请勿在实践中使用。

内部类具有这种独特的行为,其中所有构造函数都在第一个位置隐式声明封闭类型的参数。所以,

public class file1 {
    public class Inner {
    }
}

实际上被编译成类似的东西

public class file1 {
    public class Inner {
        public Inner(file1 enclosing) {
        }
    }
}

whereenclosing实际上是Outer对其初始化的封闭实例的引用。

new file1().new Inner();
// compiles to something like
file1 enclosing = new file1();
new Inner(enclosing);

请记住,对于常规继承,如果超类声明了一个参数化构造函数(并且没有无参数构造函数),则子类必须使用super(...)它自己的构造函数来调用它。通过内部类的继承,如果还隐式提供了封闭实例,则可以隐式super(...)执行该调用。

file3也就是说,如果实际上也是file1(或file2)的内部类,而不是嵌套类,则您的类层次结构将被编译。

public class file2 extends file1 {
    public class file3 extends file2.Inner {
    }
}

正如我之前所说,file3将编译为类似

public class file3 extends file2.Inner {
    public file3(file2 enclosing) {
        super(enclosing); // this is calling the `public Inner(file1)` constructor
    }
}

由于“类型的封闭实例在范围内” ,因此该调用将隐式super(..)完成。file1

但是,由于您的file3类不是file1nor的内部类file2,因此没有隐式封闭file1实例可以传递给超级构造函数,因此 Java 编译器会产生您看到的错误。

我一直隐含地加粗这个词,试图强调 Java 允许您显式绕过所有这些的事实。此功能是内部类独有的。Java 提供以下语法来声明带有参数(在任何位置)的构造函数,以明确地被视为封闭实例

public static class file3 extends file2.Inner {
    public file3(file2 enclosing) {
        enclosing.super(); // special syntax
    }
    // [...]
}

而且,就像常规继承一样,该super(..)调用必须是构造函数主体中的第一条语句。

然后你的main方法就变成了

file2 file2 = new file2();
file3 outer = new file3(file2);
System.out.println(outer.x);

file2.Inner您在其中明确提供(也可以通过)所需的封闭实例null


供您参考,还有显式声明我在第二个片段中提到的构造函数的语法,其中参数表示封闭实例

public class file1 {
    public class Inner {
        public Inner(@SomeAnnotation file1 file1.this) {
        }
    }
}

这仅在您要注释参数时才真正有用。

这些信息分布在Java 语言规范的第 8 章中,特别是关于“内部类”和“接收器参数”的部分。


推荐阅读