我知道要实例化成员内部类,需要两个不同的构造函数:
第一:
Outer out = new Outer();
Outer.Inner in = out.new Inner();
第二:
Outer.Inner in = new Outer().new Inner();
现在,我不知道为什么这个代码会编译:
public class Outer {
private String greeting="Hi";
protected class Inner {
public int repeat=3;
public void go() {
for (int i =0; i<repeat; i++) {
System.out.println(greeting);
}
}
}
public void callInner() {
Inner in = new Inner(); //in my opinion the correct constructor is Outer.Inner in = new Inner()
in.go();
}
public static void main(String[] args) {
Outer out = new Outer();
out.callInner();
}
}
为什么要编译?
非常感谢!
当您在Outer
的范围内(在实例方法内(实例化Inner
时,您不需要显式实例化引用Outer
类,就像您的示例中一样:
Outer.Inner in = new Outer().new Inner();
只引用Inner
:实例化是可以的
Inner in = new Inner();
这适用于类中的所有实例方法,只要它们不是静态的。
第一个主方法将被称为
public static void main(String[] args){
Outer out = new Outer();
out.callInner();
}
从这里开始,您创建了一个Outer类的对象,并称之为callInner方法,如下所示
public void callInner() {
Inner in = new Inner(); //in my opinion the correct constructor is Outer.Inner in = new Inner()
in.go();
}
现在您已经创建了一个名为"内部"的对象,并称之为go方法。
protected class Inner {
public int repeat=3;
public void go() {
for (int i =0; i<repeat; i++) {
System.out.println(greeting);
}
}
}
所以这是一个简单的调用,所有调用都在同一范围内。因此需要外部。内部概念调用。
重要的是要理解外在和内在是相关的。更具体地说,您需要一个外部实例才能创建内部实例。
Outer
的实例来创建Inner
的实例。由于方法callInner
是Outer
的实例方法(未声明为static
(,因此已经存在Outer
的实例:this
代码也可以这样写:
public void callInner() {
Outer out = this;
Inner in = out.new Inner();
in.go();
}
现在,代码看起来与您的第一个示例相似。
但让我们保持代码如图所示:
public void callInner() {
Inner in = new Inner();
in.go();
}
现在,如果我们从引擎盖下看,它基本上是一样的:
public void callInner();
Code:
0: new #21 // class playground/Outer$Inner
3: dup
4: aload_0
5: invokespecial #23 // Method playground/Outer$Inner."<init>":(Lplayground/Outer;)V
8: astore_1
9: aload_1
10: invokevirtual #26 // Method playground/Outer$Inner.go:()V
13: return
在第4行,我们得到了aload_0
,它加载了实例方法this
。
比较:Java教程-内部类示例
当您调用callInner
方法时,您实际上在Outer
类的范围内。编译器接受调用new Inner()
的原因是完全一样的,为什么你不必明确地写你想象中的静态变量来自哪个类(当它是你调用它的同一类的一部分时(。参见以下示例:
public class Outer {
private static int x = 1;
private void innerCall() {
x++;
}
}
在上面的情况下,除了使用类而不是变量(这在这里并不真正相关(之外,您所做的与示例中完全相同。如果希望从类(作用域(外部访问类/变量,则需要使用语法。然后它看起来像下面的东西:
public class Outer {
public static int x = 1;
}
Outer.x++;
上面,您必须明确指定要从哪个范围访问变量x
。这就像您想要从给定目录中访问文件一样。如果你在这个目录中,你只需要按文件名访问它。然而,当你在它之外时,你还必须写下目录的名称,才能看到你想要得到的文件。