关于java:是否有与嵌套类关联的构造函数

Is there a constructor associated with nested classes

我想知道是否有任何构造函数涉及到内部类。例如,考虑下面给出的代码片段

1
2
3
4
5
6
7
8
9
10
11
class MyOuter
{
   private int x= 10;

   class MyInner
   {
      void dostuff(){
         System.out.println("The value of x is"+x);
      }
   }
}

在另一个Java文件中,我为MyOuter和MyLype类创建实例,如下所示

1
2
3
4
5
6
7
8
9
Class Program
{
   public static void main(String [] args)
   {
      MyOuter mo = new MyOuter();
      MyOuter.MyInner mi = mo.new MyInner();
      mi.dostuff();
   }
}

上面的代码片段编译得很好,给出了"x的值是10"的输出。

这里我想知道的是,当new()与myinner类和myouter类一起使用时,是否调用构造函数。如果是,那么是否存在从内部类到外部类的任何构造函数链接(比如子类调用超级类的构造函数等等)。


在扩展内部类时,可以观察内部类的构造函数链。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MainClass {

    public MainClass(String value) {
        System.out.println("mainValue:" + value);
    }

    public class NestedClass {

        public NestedClass(String nestedValue) {
            System.out.println("nestedValue:" + nestedValue);
        }
    }

}

然后像这样扩展嵌套类

1
2
3
4
5
6
public class NestedClassExtension extends NestedClass {

    public NestedClassExtension(MainClass mainClass, String nestedValue) {
        mainClass.super(nestedValue);
    }
}

因此,您可以看到,您能够调用嵌套类的超级构造函数,将它传递给该构造函数MainClass,并在MainClass对象实例上调用.super

现在,可以通过以下方式创建嵌套类扩展实例:

1
NestedClassExtension extension = new NestedClassExtension(new MainClass("main"),"nested");

所以主类必须存在,它的构造函数被称为第一个。然后是嵌套类的构造函数。

相反,如果要在MainClass之外创建NestedClass实例,则必须编写:

1
2
MainClass mc = new MainClass("main");
mc.new NestedClass("nested");

另一次,必须先创建MainClass,然后创建嵌套类。


只有在

1
MyOuter.MyInner mi = mo.new MyInner();

否则,它甚至不会调用内部类构造函数,因为它没有被实例化,就像执行静态块一样,但在创建对象之前,不会调用实例块和构造函数。


它们都是使用默认的无参数构造函数实例化的。继承的super()中没有类似的链接。只是如果不先实例化外部类,就不能实例化内部类。

读取静态和非静态内部类之间的区别。


如果不指定构造函数,将创建不带参数的默认构造函数。如果您声明任何其他构造函数,比如myinner(int i),那么缺省构造函数的创建将被省略,并且您必须自己声明它(如果需要)。每个对象(没有任何异常)都是通过调用构造函数创建的。


如果编译了建议的代码,然后运行Java反编译程序

1
javap MyOuter$MyInner

您将看到编译器如何实际声明内部类的构造函数:

1
2
3
4
5
public class MyOuter$MyInner extends java.lang.Object{
    final MyOuter this$0;
    public MyOuter$MyInner(MyOuter);
    void dostuff();
}

在这里,您可以看到编译器通过声明包含对封闭类的引用的最后一个字段成员来实现内部类。字段被声明为最终字段,因此需要提供一个值来实例化您的Inner类。

执行MyOuter.MyInner mi = mo.new MyInner()操作时,编译器确保将封闭实例作为参数传递。

这是由编译器自动完成的,因此,您不能简单地将内部类的创建与外部类的创建链接起来,因为外部实例在您创建内部实例时必须已经存在。

但是,您可以在内部类的其他声明的构造函数之间进行构造函数链接。

例如,如果这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyOuter
{
   private int x= 10;

   public class MyInner
   {
        private int y = 0;

        public MyInner(){
            this(10);
        }

        public MyInner(int value){
            this.y = value;
        }

        void doStuff(){
            System.out.println("The value of x is"+x);
        }
   }
}

在这里,我将构造函数与内部类链接起来。

同样,反编译器确保解释所有这些内容,以确保将外部实例作为参数传递给内部实例:

1
2
3
4
5
6
public class MyOuter$MyInner extends java.lang.Object{
    final MyOuter this$0;
    public MyOuter$MyInner(MyOuter);
    public MyOuter$MyInner(MyOuter, int);
    void doStuff();
}