11

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

class MyOuter
{
   private int x= 10;

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

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

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 类一起使用时是否调用了构造函数。如果是,那么是否有任何构造函数从内部类链接到外部类(例如子类调用超类的构造函数等)。

4

5 回答 5

15

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

举个例子:

public class MainClass {

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

    public class NestedClass {

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

}

然后像这样扩展 NestedClass

public class NestedClassExtension extends NestedClass {

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

因此您可以看到您可以调用嵌套类的超级构造函数,并将其传递给该构造函数,MainClass并调用对象实例。.supermainClass

现在您可以通过这种方式创建 NestedClassExtension 实例:

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

所以主类必须存在,它的构造函数首先被调用。然后是嵌套类的构造函数。

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

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

还有一次,MainClass必须先创建,然后再创建嵌套类。

于 2012-04-13T06:15:27.820 回答
4

仅当您拥有内部构造函数时才会调用

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

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

于 2012-04-13T05:59:31.360 回答
2

如果您不指定构造函数,则会创建一个不带参数的默认构造函数。如果您声明任何其他构造函数说 MyInner(int i) ,则默认构造函数的创建被省略,您必须自己声明它(如果需要)。每个对象(没有任何例外)都是通过调用构造函数创建的。

于 2012-04-13T05:59:53.247 回答
2

它们都使用默认的无参数构造函数进行实例化。没有像继承的 super() 那样的链接。只是你不能在没有先实例化外部类的情况下实例化一个内部类。

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

于 2012-04-13T06:00:59.487 回答
1

如果您编译建议的代码,然后在其上运行 Java 反编译器

javap MyOuter$MyInner

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

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

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

当您这样做时MyOuter.MyInner mi = mo.new MyInner(),编译器会确保封闭实例作为参数传递。

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

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

例如,如果这样的代码:

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);
        }
   }
}

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

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

public class MyOuter$MyInner extends java.lang.Object{
    final MyOuter this$0;
    public MyOuter$MyInner(MyOuter);
    public MyOuter$MyInner(MyOuter, int);
    void doStuff();
}
于 2012-04-13T06:21:35.960 回答