清楚解释Java中的构造函数链(附实例)

541 阅读3分钟

在Java中,构造函数链是指在同一上下文对象中从另一个构造函数调用一个构造函数的过程。

构造函数链对于避免代码中的重复是非常有用的,同时提供了在不同情况下使用的多个构造函数。

构造函数链可以通过两种方式完成:

  • 你可以使用this() 函数从同一个类中调用其他构造函数。
  • 你可以使用super() 关键字来调用超类或基类的构造函数。

让我们看一个构造函数链的实例。

假设你有一个Product 类,其定义如下:

class Product {
String name;
int price;
// constructor 1
 Product() {
this.name = "Car";
this.price = 0;
}
// constructor 2
 Product(String name) {
this.name = name;
this.price = 0;
}
// constructor 3
 Product(String name, int price) {
this.name = name;
this.price = price;
}
}

在上面的Product 类中定义了3个构造函数,使你可以灵活地初始化一个新的Product 对象。

这3个构造函数都可以单独使用,如下所示:

Product prod = new Product(); // Car, 0
Product prod2 = new Product("Phone"); // Phone, 0
Product prod3 = new Product("Phone", 55); // Phone, 55

但实际上你可以在你的Product 类中使用构造函数链来实现同样的结果。

请看下面的例子:

class Product {
String name;
int price;
Product() {
 this("Car");
 }
Product(String name) {
 this(name, 0);
 }
Product(String name, int price) {
this.name = name;
this.price = price;
}
}

在上面的新Product 类中,该类的前两个构造函数调用另一个构造函数来初始化类成员。

这个更新后的类产生的结果与之前的类相同,但构造函数内写的代码更少。

使用super()的构造函数链

除了避免多余的代码外,构造函数链还可以被子类用来调用超类的构造函数。

例如,假设你有一个Baby 类,它是Human 类的一个子类,如下图所示:

class Baby extends Human {
Baby(String name) {
this.name = name;
}
}
class Human {
String name;
int fingers;
Human() {
this.fingers = 5;
}
}

在构建Human 类的过程中,fingers 属性被赋值为5

但是当你创建一个新的Baby 对象时,这就是fingers 属性的输出:

Baby lisa = new Baby("Lisa");
System.out.println(lisa.fingers); // 5

Baby 类的构造函数只分配了name 属性的值时,lisa.fingers 怎么会返回5

这是因为在运行子类构造函数之前,Java会自动调用超类构造函数。

上述Baby 类的执行方式如下:

class Baby extends Human {
Baby(String name) {
 super();
 this.name = name;
}
}

但请记住,只有没有任何参数的默认构造函数super() ,才会被子类调用。

如果你有一个带有一个或多个参数的超级构造函数,你需要在子类中明确地调用它。

假设Human 类有第二个构造函数,添加一个superpower ,如下图所示:

class Human {
String name;
int fingers;
String superpower;
 Human(String superpower){
 this.fingers = 5;
this.superpower = superpower;
}
}

如果没有默认的Human() 构造函数,Baby() 构造函数行将抛出一个错误,说There is no default constructor in Human

你需要明确地调用super() ,如下图所示:

class Baby extends Human {
Baby(String name) {
 super("Breathe underwater");
 this.name = name;
}
}

上面的super() 调用应该可以解决没有默认构造函数的错误。

构造函数链的规则

Java有一些关于构造函数链的规则,如下:

  • 带有this()super() 关键字的构造器调用必须是任何调用另一个构造器的构造器的第一行。
  • 每个class ,至少需要一个不调用另一个构造器的构造器。这是为了避免构造函数调用的无限循环。

关于构造函数链的顺序没有规定,但一个常见的经验法则是,参数少的构造函数应该调用参数多的构造函数

构造函数链是Java包中经常使用的功能之一,因为它能使类变得灵活。

现在你已经了解了构造函数链在Java中是如何工作的。

你还看到了一个实际的例子,其中构造函数链减少了代码的冗余,并调用了超类的构造函数。

我希望这个教程对你有用🙏