Java中的构造函数链接

时间:2020-01-09 10:34:48  来源:igfitidea点击:

Java中的构造函数链接是从同一个类中的另一个构造函数调用一个构造函数或者从子类调用父类构造函数的过程。

因此,Java中的构造函数链接可以通过两种方式完成:

  • 在同一个类中从另一个构造函数调用一个构造函数时。在这种情况下,该关键字可用于调用链中的构造函数。
  • 从子类调用父类的构造函数时,如果继承。在这种情况下,可以使用super关键字来调用构造函数。

构造函数链接如何提供帮助

Java中的构造函数链接通过在其中一个构造函数中执行初始化任务来帮助减少代码冗余。所有其他构造函数仅在链中调用该构造函数进行初始化。

考虑这样一种情况:班级中有3个字段,并且希望提供一个选项来初始化它们中的所有一个或者两个,或者仅初始化一个或者一个。如果在所有构造函数中都保留初始化,则代码将如下所示。

没有构造函数链接的代码

public class ConstrChaining {
  int a;
  double b;
  String name;
  ConstrChaining(){

  }
  ConstrChaining(int a){
    this.a = a;
  }
  ConstrChaining(int a, double b){
    this.a = a;
    this.b = b;
  }
  ConstrChaining(int a, double b, String name){
    this.a = a;
    this.b = b;
    this.name = name;
  }
  ..
  ..
}

如我们所见,构造函数中包含初始化代码的冗余。通过使用构造函数链接,一个构造函数调用另一个相同的代码,可以编写如下。

带构造函数链接的代码

public class ConstrChaining {
  int a;
  double b;
  String name;
  ConstrChaining(){
    this(0);
  }
  ConstrChaining(int a){
    this(a, 0.0);
  }
  ConstrChaining(int a, double b){
    this(a, b, null);
  }
  ConstrChaining(int a, double b, String name){
    this.a = a;
    this.b = b;
    this.name = name;
  }
  public static void main(String[] args) {
    ConstrChaining cc = new ConstrChaining();
    System.out.println("a- " + cc.a + " b- " + cc.b + " name- " + cc.name);
    
    ConstrChaining cc1 = new ConstrChaining(5, 7.8);
    System.out.println("a- " + cc1.a + " b- " + cc1.b + " name- " + cc1.name);
    
    ConstrChaining cc2 = new ConstrChaining(18, 13.45, "theitroad");
    System.out.println("a- " + cc2.a + " b- " + cc2.b + " name- " + cc2.name);
  }
}

输出:

a- 0 b- 0.0 name- null
a- 5 b- 7.8 name- null
a- 18 b- 13.45 name- theitroad

就像我们现在看到的那样,初始化是由类中的单个构造函数完成的,所有其他构造函数都只是在链中调用该构造函数,而不是自己进行初始化。

Java中带有继承的构造函数链接

在继承的情况下,构造函数链接是从子类调用父类构造函数的过程。无需再次初始化父类的字段,而是可以在子类的构造函数中使用super关键字调用父类的构造函数。这有助于减少代码重复。

public class Area {
  int length;
  int width;
  Area(int length, int width){
    this.length = length;
    this.width = width;
  }
  public static void main(String[] args) {
    Volume volume = new Volume(5,6,7);
    System.out.println("length-" + volume.length + " width-" + 
      volume.width + " height-" + volume.height);
  }
}

class Volume extends Area{
  int height;
  Volume(int length, int width, int height){
    // Calling constructor of parent class
    super(length, width);
    this.height = height;
  }
}

输出:

length-5 width-6 height-7

在此示例中,我们可以看到使用超关键字从子类构造函数中调用了父类构造函数,以初始化父类的字段。

有关使用super构造函数链接的规则

  • 如果在构造函数中使用super()来调用父类的构造函数,则它必须是构造函数中的第一条语句,否则会出现编译时错误"构造函数调用必须是构造函数中的第一条语句"。

  • 如果我们未显式调用父类构造函数,则每个超类的默认no-arg构造函数将隐式执行。

  • 如果构造函数从子类链接到父类(继承层次结构),则调用构造函数的顺序是从父类到子类。

让我们看一个例子。

class A{
  A(){
    System.out.println("In the constructor of class A");
  }
}

class B extends A{
  int i;
  B(int i){
    this.i = i;
    System.out.println("In the constructor of class B");
  }
}
class C extends B{
  C(int i){
    super(i);
    System.out.println("In the constructor of class C");
  }
  public static void main(String[] args) {
    C c = new C(5);
  }
}

在此代码中,A是由类B扩展的超类,而类B又由类C扩展。

当我们创建C类的对象时,将在从超类到子类的链中调用超类构造函数,输出如下。

In the constructor of class A
In the constructor of class B
In the constructor of class C

还要注意,从类B的构造函数开始,仍未显式调用类A的构造函数,但仍会调用它,因为超类的默认no-arg构造函数将隐式执行。