📜  Java中的构造函数链接(带示例)

📅  最后修改于: 2020-04-02 14:00:14             🧑  作者: Mango

先决条件: Java中的构造函数
构造函数链接是相对于当前对象从另一个构造函数调用一个构造函数的过程。
构造函数链接可以通过两种方式完成:

  • 在同一个类中:对于同一个类中的构造函数,可以使用this()关键字来完成
  • 从基类:通过使用super()关键字从基类调用构造函数。

构造函数链接通过继承发生。子类构造函数的任务是首先调用超类的构造函数。这样可以确保子类对象的创建始于超类的数据成员的初始化。继承链中可以有任意多个类。每个构造函数都会调用链,直到到达顶部的类为止。

为什么我们需要构造函数链接?
当我们要在单个构造函数中执行多个任务而不是在单个构造函数中为每个任务创建代码时,会使用此过程,而是为每个任务创建一个单独的构造函数并使其链条化,从而使程序更具可读性。

使用this()关键字在同一类中进行构造函数链接:

 

// Java使用this构造函数进行链接
class Temp
{
    // 默认构造函数1
    Temp()
    {
        // 调用构造函数2
        this(5);
        System.out.println("默认构造函数");
    }
    // 参数化构造函数2
    Temp(int x)
    {
        // 调用构造函数3
        this(5, 15);
        System.out.println(x);
    }
    // 参数化构造函数 3
    Temp(int x, int y)
    {
        System.out.println(x * y);
    }
    public static void main(String args[])
    {
        // 第一次调用构造函数
        new Temp();
    }
}

输出:

75
5
默认构造函数

构造函数链接规则:

  1. 此()表达应该总是构造函数的第一行。
  2. 至少应该有一个没有this()关键字的构造函数(上例中的构造函数3)。
  3. 构造函数链接可以以任何顺序实现。

如果我们更改构造函数的顺序会怎样?

没什么,构造函数链接可以任何顺序实现

// Java展示构造函数链接可以任何顺序实现
class Temp
{
    // 默认构造函数1
    Temp()
    {
        System.out.println("默认构造函数");
    }
    // 参数构造函数2
    Temp(int x)
    {
        // 调用默认构造函数
        this();
        System.out.println(x);
    }
    // 参数构造函数3
    Temp(int x, int y)
    {
        // 调用构造函数2
        this(5);
        System.out.println(x * y);
    }
    public static void main(String args[])
    {
        // 调用构造函数3
        new Temp(8, 10);
    }
}

输出:

默认构造函数
5
80

注意:在示例1,最后调用默认构造函数,但是在示例2中,首先调用默认构造函数。因此,构造函数链接中的顺序并不重要。

使用super()关键字将构造函数链接到其他类:

// Java 使用super()关键字将构造函数链接到其他类
class Base
{
    String name;
    // 构造函数 1
    Base()
    {
        this("");
        System.out.println("无参数构造函数" +
                                           " 基类");
    }
    // 构造函数 2
    Base(String name)
    {
        this.name = name;
        System.out.println("参数构造函数"
                                              + " 基类");
    }
}
class Derived extends Base
{
    // 构造函数 3
    Derived()
    {
        System.out.println("无参数构造函数 " +
                           "派生类");
    }
    // 参数构造函数 4
    Derived(String name)
    {
        // 调用基类构造函数2
        super(name);
        System.out.println("参数构造函数 " +
                           "派生类");
    }
    public static void main(String args[])
    {
        // 调用参数构造函数 4
        Derived obj = new Derived("test");
        // 调用无参数构造函数
        // Derived obj = new Derived();
    }
}

输出:

参数构造函数 基类
参数构造函数 派生类

注意:类似于同一类中的构造函数链接,super()应该是构造函数的第一行,因为在子类的构造函数之前调用了超类的构造函数。
替代方法:使用Init块
当我们希望每个构造函数都执行某些公共资源时,可以将代码放入init块中。每当使用构造函数创建新对象时,始终在任何构造函数之前执行Init块。
范例1:

class Temp
{
    // 构造函数之前被执行的block.
    {
        System.out.println("初始化块");
    }
    // 非参数构造器
    Temp()
    {
        System.out.println("默认");
    }
    // 一个参数构造函数.
    Temp(int x)
    {
        System.out.println(x);
    }
    public static void main(String[] args)
    {
        // 非参数构造函数被调用
        new Temp();
        // 参数构造函数被调用
        new Temp(10);
    }
}

输出:

初始化块
默认
初始化块
10

注意:如果有多个块,则按照在同一类中定义的顺序执行它们。见前。
范例:

class Temp
{
    // 先被执行的部分
    {
        System.out.println("初始化");
    }
    Temp()
    {
        System.out.println("默认");
    }
    Temp(int x)
    {
        System.out.println(x);
    }
    // block to be executed after the first block
    // which has been defined above.
    {
        System.out.println("二");
    }
    public static void main(String args[])
    {
        new Temp();
        new Temp(10);
    }
}

输出:

初始化
二
默认
初始化
二
10