java中多级inheritance中构造函数调用的顺序

//: c07:Sandwich.java // Order of constructor calls. // package c07; // import com.bruceeckel.simpletest.*; import java.util.*; class Meal { Meal() { System.out.println("Meal()"); } } class Bread { Bread() { System.out.println("Bread()"); } } class Cheese { Cheese() { System.out.println("Cheese()"); } } class Lettuce { Lettuce() { System.out.println("Lettuce()"); } } class Lunch extends Meal { Lunch() { System.out.println("Lunch()"); } } class PortableLunch extends Lunch { PortableLunch() { System.out.println("PortableLunch()");} } public class Sandwich extends PortableLunch { // private static Test monitor = new Test(); private Bread b = new Bread(); private Cheese c = new Cheese(); private Lettuce l = new Lettuce(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); /* monitor.expect(new String[] { "Meal()", "Lunch()", "PortableLunch()", "Bread()", "Cheese()", "Lettuce()", "Sandwich()" }); // */ } } ///:~ 

这段代码的输出是

 Meal() Lunch() PortableLunch() Bread() Cheese() Lettuce() Sandwich() 

由于类中的字段是按声明的顺序创建的,为什么不这样做

 Bread() Cheese() Lettuce() 

来到上面列表的顶部?

此外,它在这段代码中尝试做什么?

  monitor.expect(new String[] { "Meal()", "Lunch()", "PortableLunch()", "Bread()", "Cheese()", "Lettuce()", "Sandwich()" }); 

起初我以为这是一个匿名类,但它看起来不像。 它是在初始化一个String数组吗? 为什么它没有String变量的名称? 请告诉我这里使用的编程结构的名称。

构造函数:

 public Sandwich() { System.out.println("Sandwich()"); } 

由编译器翻译为:

 public Sandwich() { super(); // Compiler adds it if it is not explicitly added by programmer // All the instance variable initialization is moved here by the compiler. b = new Bread(); c = new Cheese(); l = new Lettuce(); System.out.println("Sandwich()"); } 

因此,构造函数中的第一个语句是超类构造函数的链接。 实际上,对于那个问题,任何构造函数链中的第一个语句都是超类构造函数。 这就是为什么首先调用超类构造函数PortableLunch ,由于编译器添加了super() ,因此再次将调用链接到它的超类构造函数(记住吗?)。

构造函数调用的这种链接一直持续到inheritance层次结构顶部的类,从而在最后调用Object类构造函数。

现在,在每个超类构造函数执行完毕并且所有超类字段都已初始化之后,直接子类构造函数在super()调用之后开始执行。 最后它回到了Sandwitch()构造函数,它现在初始化了3字段。

因此,基本上你的字段最后被初始化,因此它们在最后打印,就在打印Sandwitch()之前。

有关实例创建过程的详细说明,请参阅JLS – 第12.5节 – 创建新类实例


至于你问题的第二部分:

 monitor.expect(new String[] { "Meal()", "Lunch()", "PortableLunch()", "Bread()", "Cheese()", "Lettuce()", "Sandwich()" }); 

此代码创建一个未命名的数组 ,并同时初始化一些字符串文字。 它类似于创建命名数组的方式:

 String[] arr = new String[] { "rohit", "jain" }; 

示例中的对象使用inheritance,这会导致调用一系列构造函数。 使用inheritance时,从另一个( subtype )inheritance的类必须调用它扩展的类的构造函数( super type )。 当存在类型层次结构时,意味着几个类在链中相互扩展,对超级构造函数的调用将传播到链中的第一个类,该类不从另一个类inheritance(忽略Object)。

必须在执行子类型构造函数之前调用子类的超类构造函数,因为它可能依赖于超类型中的字段或方法。 构造函数调用链接类型层次结构,并且每个构造函数初始化后,子类型开始实例化。

一旦调用了类类型层次结构中的超类型构造函数,就会声明子类型的字段,因为子类型的构造函数也可能需要它们。 声明子类型的字段后,执行子类型构造函数。

此顺序是必要的,因为子类型可能依赖于在超类型中建立的字段或方法。

 Meal() (Top of Class Hierarchy, not including Object) Lunch() (Extends Meal) PortableLunch() (Extends Lunch) Bread() (Field of lunch declared before constructor call) Cheese() (Field of lunch declared before constructor call) Lettuce() (Field of lunch declared before constructor call) Sandwich() (Extends Portable Lunch) 

以下是Java中对象创建的非常好的概述。

 new String[] { "Meal()", "Lunch()", "PortableLunch()", "Bread()", "Cheese()", "Lettuce()", "Sandwich()" } 

\以上是匿名数组声明 。 在这种情况下,您无需指定大小。

在初始化实例变量之前,将首先调用所有超类构造函数。 即

订单—>

  Object(), all your superclass constructors, instance variables of this class in that order 

首先调用构造函数,然后根据Java语言规范中指定的顺序评估其实例变量。 这就是你得到的原因

 Bread() Cheese() Lettuce() 

 Meal() Lunch() PortableLunch() 

关于String []初始化,你认为不是一个匿名类,只是一个String对象创建,它不一定必须分配给一个变量。