当前位置: 首页 > 面试题库 >

Java多级继承中构造函数调用的顺序

濮阳景天
2023-03-14
问题内容

//: 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() 编译器的添加(记住吗?),它又将调用链接到其超类构造函数。

完成构造函数调用的链接,直到该类位于继承层次结构的顶部,从而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" };


 类似资料:
  • 问题内容: 在为期末考试而学习时,我在正在学习的书中遇到了以下陈述。考虑以下代码: 是否必须在类B(super(x))的构造函数中调用类A的构造函数。本书指出这不是强制性的,因为它们具有确切数量和类型的参数。但是,当我在Java编译器中尝试此操作时,会抛出以下错误: 类A中的构造函数A不能应用于给定类型;必需:发现整数:无参数原因:实际和正式参数列表的长度不同 问题答案: 编译器会自动插入开头。

  • 问题内容: 我想知道为什么在Java中不继承构造函数?你知道当你上这样的课时: 稍后当你从继承时Super,java会抱怨没有定义默认的构造函数。解决方案显然是这样的: 这段代码是重复的,而不是干的和无用的(IMHO)…因此再次带来了问题: 为什么Java不支持构造函数继承?不允许这种继承有什么好处? 问题答案: 假设构造函数是继承的…则因为每个类最终都派生自Object,所以每个类最终都将带有无

  • 问题内容: 我想要一个构造函数,其参数会自动被所有子类继承,但是Java不允许我这样做 我不希望有写,等等。每个子类。有没有更聪明的方法来解决这个问题? 解决方案#1。构造一个可以在构造函数之后调用的方法。尽管对我的特定设计而言,这是可行的,但是我希望要求用户在构造函数中指定在编译时经过验证的某些参数(例如,不通过varargs / reflection)。 问题答案: 你不能 如果要在基类中有一

  • 所以,我正在做一个家庭作业,我很难遵循一些指示,我把作业贴在下面: 创建一个由五个类组成的层次结构,加上一个作为变量包含在里面的类: Person有四个字符串变量:姓名,地址,电话,电子邮件 学生是Person的子类,有一个额外的int变量状态,其值为1,2,3或4,代表大一,大二,大三,大四 MyDate有三个int变量,分别为年、月和日 员工是Person的子类,有一个String变量offi

  • 问题内容: 考虑下面的代码 基于我对类成员初始化和构造函数执行顺序的理解。我期望输出是 因为我相信类成员甚至在调用main方法之前就已初始化。但是当我运行程序时,我得到以下输出 我的困惑是,尽管Meal()Lunch()和PortableLunch()在Bread()Cheese()和Lettuce()之前运行,即使它们的构造函数被调用。 问题答案: 这些是实例字段 它们仅在创建实例时存在(执行)

  • 人们有时会对类成员函数或成员变量的作用域问题感到困惑,尤其是,当基类与派生类的同名成员不在同一个作用域内时: struct B { void f(double); }; struct D : B { void f(int); }; B b; b.f(4.5); // OK // 调用的到底是B::f(doube)还是D::f(int)呢? // 实际情况往往会让人感到意外