"no enclosing instance of type file1 is in scope" 内部错误 类
"no enclosing instance of type file1 is in scope" error with inner classes
我有一些代码(本质上它导入了另一个 class,它有一个我正在尝试访问的内部 class),但它引发了这个错误:
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;
}
}
问题
您正在尝试将嵌套 class 设为内部 class 的子 class,而这实际上不可能按照您的方式进行。有一种方法可以做到这一点,请参阅 Savior 的语法答案,但在您的情况下,它对您没有帮助。嵌套 class 和内部 class 之间的主要区别在于内部 class 绑定到外部 class 的特定实例,而嵌套 class 与任何特定实例无关。为了说明这种差异,让我们稍微修改一下您的代码:
public class file1 {
private int x;
public file1(int x) {
this.x = x;
}
// No static keyword, so this is an inner class:
protected class Inner {
public void printXInner() {
// This is legal:
System.out.println(x);
}
}
// Has static keyword, so this is a nested class:
protected static class Nested {
public void printXNested() {
// This is NOT legal:
System.out.println(x);
}
}
}
printXInner()
方法是完全合法的,因为 Inner
绑定到 file1
的特定实例,因此它可以访问特定实例(非静态)字段 x
。但是,printXNested()
方法会抛出编译时异常,因为它不知道 你要使用哪个 x
。您可以有很多 file1
的实例,每个实例可以有不同的 x
.
值
现在,为什么这很重要,它与您的代码有什么关系?好吧,假设 Java 刚刚决定允许您尝试做的事情;你可以扩展内部 classes。如果我们仍然使用上面修改后的代码,我们可以这样写:
public class file2 extends file1.Inner {
public void printXFile2() {
printXInner(); // Uh oh, what should the program do here?
}
}
这段代码看起来完全无害,它扩展了 Inner
并调用了 printXInner()
方法。除了我们的老问题再次出现:which x
should print?我们没有指定要使用 file1
的哪个实例。因此,您实际上是在尝试在静态上下文中使用内部 class。
现在,希望您在想“好吧,我明白为什么会出现问题,但我该如何解决呢?”您基本上有两个选择:您可以将内部 class 更改为嵌套 class,您可以将 file2
class 更改为内部 class ].您选择哪个选项将取决于您的代码结构。您需要决定是否要将 Inner
绑定到 file1
的特定实例。
修复 #1
将内部 class 更改为嵌套 class。如果您不需要从嵌套 class 访问特定于实例的数据,这就是方法。也许你有一辆车 class,你想为轮子嵌套 class。如果我们在汽车零件商店的意义上谈论这个,轮子不连接到任何汽车,所以我们不希望我们的嵌套 class 连接到外部 class。只需像这样修改 file1
:
public class file1 {
// Added static keyword:
protected static class Nested {
public int x = 8;
}
}
修复#2
使 subclass 扩展 superclass 的特定实例的内部 class。如果您需要从内部 class 访问特定于实例的数据,这就是方法。也许你有一辆车 class,你想要一个内轮 class。如果我们是从驾驶模拟器的角度来谈论这个,那么车轮就会连接到特定的汽车上,并且它们会保持连接。因此,我们希望我们的内部 class 附加到外部 class 的特定实例。只需像这样修改 file3
:
public class file2 extends file1 {
// Removed static keyword:
public class file3 extends Inner { ... }
}
但这可能会产生次要问题。你不能在内部 class 中有一个 main 方法,因为在启动时,没有外部 class 的实例,所以 JRE 不能调用内部 class 的方法].解决方法是将主要方法放在外部 class 中,然后从那里调用特定实例的方法。你可以这样实现:
public class file2 extends file1 {
public static void main(String[] args) {
new file2().file3.doSomething();
}
public class file3 extends Inner {
public static void doSomething() {
file3 instance = new file3();
System.out.println(instance.x);
}
}
}
TL;DR
内部 classes 与嵌套 classes 不同。内部 classes 绑定到外部 class 的特定实例,而嵌套 classes 不绑定到任何特定实例。您不能在不指定实例的情况下引用内部 class,因为这违反了内部 class.
的定义
仅供学习,切勿在实践中使用。
内部 classes 具有这种独特的行为,其中所有构造函数 隐式 在第一个位置声明封闭类型的参数。所以,
public class file1 {
public class Inner {
}
}
实际上被编译成类似
的东西
public class file1 {
public class Inner {
public Inner(file1 enclosing) {
}
}
}
其中 enclosing
实际上是对其初始化的封闭 Outer
实例的引用。
new file1().new Inner();
// compiles to something like
file1 enclosing = new file1();
new Inner(enclosing);
请记住,对于常规继承,如果 superclass 声明了一个参数化构造函数(并且没有无参数构造函数),则 subclass 必须使用 super(...)
来调用它自己的构造函数。通过内部 classes 的继承,如果还提供了封闭实例 隐式 ,则可以 隐式 调用 super(...)
.
也就是说,如果 file3
实际上也是 file1
(或 file2
)的内部 class,那么您的 class 层次结构将会编译,而不是嵌套的 class.
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
class 不是 file1
的内部 class 也不是 file2
,所以没有 implicit 包含要传递给超级构造函数的 file1
实例,因此 Java 编译器会产生您看到的错误。
我一直将 隐式 这个词加粗,试图强调 Java 可以让你 显式 绕过所有这些。此功能是内部 classes 所独有的。 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) {
}
}
}
这真的只有在您想注释参数时才有用。
此信息分布在 Chapter 8 of the Java Language Specification,特别是关于“内部 classes”和“接收器参数”的部分。
我有一些代码(本质上它导入了另一个 class,它有一个我正在尝试访问的内部 class),但它引发了这个错误:
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;
}
}
问题
您正在尝试将嵌套 class 设为内部 class 的子 class,而这实际上不可能按照您的方式进行。有一种方法可以做到这一点,请参阅 Savior 的语法答案,但在您的情况下,它对您没有帮助。嵌套 class 和内部 class 之间的主要区别在于内部 class 绑定到外部 class 的特定实例,而嵌套 class 与任何特定实例无关。为了说明这种差异,让我们稍微修改一下您的代码:
public class file1 {
private int x;
public file1(int x) {
this.x = x;
}
// No static keyword, so this is an inner class:
protected class Inner {
public void printXInner() {
// This is legal:
System.out.println(x);
}
}
// Has static keyword, so this is a nested class:
protected static class Nested {
public void printXNested() {
// This is NOT legal:
System.out.println(x);
}
}
}
printXInner()
方法是完全合法的,因为 Inner
绑定到 file1
的特定实例,因此它可以访问特定实例(非静态)字段 x
。但是,printXNested()
方法会抛出编译时异常,因为它不知道 你要使用哪个 x
。您可以有很多 file1
的实例,每个实例可以有不同的 x
.
现在,为什么这很重要,它与您的代码有什么关系?好吧,假设 Java 刚刚决定允许您尝试做的事情;你可以扩展内部 classes。如果我们仍然使用上面修改后的代码,我们可以这样写:
public class file2 extends file1.Inner {
public void printXFile2() {
printXInner(); // Uh oh, what should the program do here?
}
}
这段代码看起来完全无害,它扩展了 Inner
并调用了 printXInner()
方法。除了我们的老问题再次出现:which x
should print?我们没有指定要使用 file1
的哪个实例。因此,您实际上是在尝试在静态上下文中使用内部 class。
现在,希望您在想“好吧,我明白为什么会出现问题,但我该如何解决呢?”您基本上有两个选择:您可以将内部 class 更改为嵌套 class,您可以将 file2
class 更改为内部 class ].您选择哪个选项将取决于您的代码结构。您需要决定是否要将 Inner
绑定到 file1
的特定实例。
修复 #1
将内部 class 更改为嵌套 class。如果您不需要从嵌套 class 访问特定于实例的数据,这就是方法。也许你有一辆车 class,你想为轮子嵌套 class。如果我们在汽车零件商店的意义上谈论这个,轮子不连接到任何汽车,所以我们不希望我们的嵌套 class 连接到外部 class。只需像这样修改 file1
:
public class file1 {
// Added static keyword:
protected static class Nested {
public int x = 8;
}
}
修复#2
使 subclass 扩展 superclass 的特定实例的内部 class。如果您需要从内部 class 访问特定于实例的数据,这就是方法。也许你有一辆车 class,你想要一个内轮 class。如果我们是从驾驶模拟器的角度来谈论这个,那么车轮就会连接到特定的汽车上,并且它们会保持连接。因此,我们希望我们的内部 class 附加到外部 class 的特定实例。只需像这样修改 file3
:
public class file2 extends file1 {
// Removed static keyword:
public class file3 extends Inner { ... }
}
但这可能会产生次要问题。你不能在内部 class 中有一个 main 方法,因为在启动时,没有外部 class 的实例,所以 JRE 不能调用内部 class 的方法].解决方法是将主要方法放在外部 class 中,然后从那里调用特定实例的方法。你可以这样实现:
public class file2 extends file1 {
public static void main(String[] args) {
new file2().file3.doSomething();
}
public class file3 extends Inner {
public static void doSomething() {
file3 instance = new file3();
System.out.println(instance.x);
}
}
}
TL;DR
内部 classes 与嵌套 classes 不同。内部 classes 绑定到外部 class 的特定实例,而嵌套 classes 不绑定到任何特定实例。您不能在不指定实例的情况下引用内部 class,因为这违反了内部 class.
的定义仅供学习,切勿在实践中使用。
内部 classes 具有这种独特的行为,其中所有构造函数 隐式 在第一个位置声明封闭类型的参数。所以,
public class file1 {
public class Inner {
}
}
实际上被编译成类似
的东西public class file1 {
public class Inner {
public Inner(file1 enclosing) {
}
}
}
其中 enclosing
实际上是对其初始化的封闭 Outer
实例的引用。
new file1().new Inner();
// compiles to something like
file1 enclosing = new file1();
new Inner(enclosing);
请记住,对于常规继承,如果 superclass 声明了一个参数化构造函数(并且没有无参数构造函数),则 subclass 必须使用 super(...)
来调用它自己的构造函数。通过内部 classes 的继承,如果还提供了封闭实例 隐式 ,则可以 隐式 调用 super(...)
.
也就是说,如果 file3
实际上也是 file1
(或 file2
)的内部 class,那么您的 class 层次结构将会编译,而不是嵌套的 class.
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
class 不是 file1
的内部 class 也不是 file2
,所以没有 implicit 包含要传递给超级构造函数的 file1
实例,因此 Java 编译器会产生您看到的错误。
我一直将 隐式 这个词加粗,试图强调 Java 可以让你 显式 绕过所有这些。此功能是内部 classes 所独有的。 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) {
}
}
}
这真的只有在您想注释参数时才有用。
此信息分布在 Chapter 8 of the Java Language Specification,特别是关于“内部 classes”和“接收器参数”的部分。