Java &引用;“范围”中没有file1类型的封闭实例;内部类错误

Java &引用;“范围”中没有file1类型的封闭实例;内部类错误,java,inheritance,inner-classes,Java,Inheritance,Inner Classes,我有一些代码(本质上它导入了另一个类,它有一个我试图访问的内部类),但它会出现以下错误: 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 fil

我有一些代码(本质上它导入了另一个类,它有一个我试图访问的内部类),但它会出现以下错误:

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);
        }
    }
}
文件1的代码:

package secret;

public class file1 {
    protected class Inner {
        public int x = 8;
    }
}
问题 您试图使嵌套类成为内部类的子类,而这实际上是不可能的。有一种方法可以做到这一点,请参阅Savior的答案,了解语法,但在您的情况下,它对您没有帮助。嵌套类和内部类之间的关键区别在于,内部类绑定到外部类的特定实例,而嵌套类不绑定到任何特定实例。为了说明这种差异,让我们稍微修改一下代码:

公共类文件1{
私人INTX;
公共文件1(int x){
这个.x=x;
}
//没有静态关键字,因此这是一个内部类:
保护类内部{
public void printXInner(){
//这是合法的:
系统输出println(x);
}
}
//具有static关键字,因此这是一个嵌套类:
受保护的静态类嵌套{
public void printXNested(){
//这是不合法的:
系统输出println(x);
}
}
}
printXInner()
方法是完全合法的,因为
internal
绑定到
file1
的特定实例,因此它可以访问特定于实例(非静态)的字段
x
。但是,
printXNested()
方法将抛出编译时异常,因为它不知道要使用哪个
x
。您可以有许多
file1
的实例,每个实例都可以有一个不同的
x

现在,为什么这很重要,它与您的代码有什么关系?好吧,假设Java刚刚决定允许您尝试做的事情;您可以扩展内部类。如果我们仍然使用上面修改过的代码,我们可以编写如下代码:

公共类file2扩展file1.Inner{
public void printXFile2(){
printXInner();//哦,程序在这里应该做什么?
}
}
这段代码似乎完全无害,它扩展了
内部
,并调用
printXInner()
方法。除了我们的老问题再次出现:它应该打印哪个
x
?我们尚未指定要使用的
file1
实例。因此,您实际上是在尝试在静态上下文中使用内部类


现在,希望您正在思考“好的,我理解为什么会有问题,但我如何解决它?”您基本上有两个选项:您可以将内部类更改为嵌套类,您可以将
file2
类更改为内部类。选择哪个选项取决于代码的结构。您需要决定是否要将
internal
绑定到
file1
的特定实例

修正#1 将内部类更改为嵌套类。如果您不需要从嵌套类访问特定于实例的数据,那么这是一种方法。也许你有一个car类,你想有一个轮子的嵌套类。如果我们从汽车零件库的角度来讨论这个问题,车轮不会附加到任何汽车上,因此我们不希望我们的嵌套类附加到外部类的任何实例上。只需像这样修改
file1

公共类文件1{
//添加了静态关键字:
受保护的静态类嵌套{
公共整数x=8;
}
}
修正2 使子类扩展超类的特定实例的内部类。如果需要从内部类访问特定于实例的数据,这是一种方法。也许你有一个汽车类,你想有一个内部的车轮类。如果我们在驾驶模拟器的意义上讨论这个问题,那么车轮连接到特定的汽车上,并且它们保持连接。因此,我们希望将内部类附加到外部类的特定实例。只需像这样修改
file3

公共类文件2扩展文件1{
//已删除静态关键字:
公共类文件3扩展内部{…}
}
不过,这可能会产生第二个问题。在内部类中不能有main方法,因为在启动时,没有外部类的实例,所以JRE不能调用内部类的方法。解决方法是将main方法放在外部类中,并从那里调用特定实例上的方法。您可以这样实现:

公共类文件2扩展文件1{
公共静态void main(字符串[]args){
新文件2().file3.doSomething();
}
公共类file3扩展了内部{
公共静态无效剂量测定法(){
file3实例=新file3();
System.out.println(instance.x);
}
}
}
TL;博士 内部类不同于嵌套类。内部类绑定到外部类的特定实例,而嵌套类不绑定到任何特定实例。如果不指定实例,就不能引用内部类,因为这违反了内部类的定义。

仅出于教育目的,请勿在实践中使用。 内部类具有这种独特的行为,其中它们的所有构造函数隐式地在第一个位置声明封闭类型的参数。所以

public class file1 {
    public class Inner {
    }
}
实际上编译为

public class file1 {
    public class Inner {
        public Inner(file1 enclosing) {
        }
    }
}
public class file3 extends file2.Inner {
    public file3(file2 enclosing) {
        super(enclosing); // this is calling the `public Inner(file1)` constructor
    }
}
file2 file2 = new file2();
file3 outer = new file3(file2);
System.out.println(outer.x);
其中
封闭
实际上是对封闭的
外部
实例的引用

new file1().new Inner();
// compiles to something like
file1 enclosing = new file1();
new Inner(enclosing);
请记住,对于常规继承,如果超类声明参数化构造函数(而不是无参数构造函数),则子类必须使用
super(…)
在其自己的构造函数中调用它。和inherita
public static class file3 extends file2.Inner {
    public file3(file2 enclosing) {
        enclosing.super(); // special syntax
    }
    // [...]
}
file2 file2 = new file2();
file3 outer = new file3(file2);
System.out.println(outer.x);
public class file1 {
    public class Inner {
        public Inner(@SomeAnnotation file1 file1.this) {
        }
    }
}