Java中你真的會用Constructor構造器嗎之看完本篇你就真的會瞭

引言

相信大傢對於java裡的構造器應該都是有瞭解的,這次我們來瞭解一些構造器的不同使用方式,瞭解構造器的調用順序,最後可以靈活的在各種情況下定義使用構造器,進一步優化我們的代碼;

構造器簡介

還是簡單介紹一下構造器到底是什麼吧,
構造器是類中一種特殊的方法,通過調用構造器來完成對象的創建,以及對象屬性的初始化操作。

構造器定義方式:

[修飾符列表] 構造器名(形式參數列表){
     構造方法體;
 }

構造器有以下幾個特點:

  • 構造器名和類名一致;
  • 構造器用來創建對象,以及完成屬性初始化操作;
  • 構造器返回值類型不需要寫,包括 void 也不能寫
  • 構造器的返回值類型實際上是當前類的類型
  • 一個類中可以定義多個構造器,這些構造器構成方法重載

構造器的使用其實很常見,調用語法為:new 構造器名(實際參數列表) ,假如我們現在有一個Person類,調用默認構造器:

Person p = new Person(); // 這裡的Person()其實就是調用的默認構造器!!

構造器的使用需要註意:
當一個類沒有顯式的定義任何構造器的時候,系統默認提供無參數構造器,當顯式的定義構造器之後,系統不再提供無參數構造器。無參數構造器又叫做缺省構造器,或默認構造器;

構造器重載

雖然系統會給我們提供默認構造器並賦予初始值,我們自己也可以顯式的指定初始值,但是可不可以多種構造器同時存在一個類中呢?
這就需要重載構造器,因為構造器也是方法的一種,方法都可以重載,構造器當然也可以;
構造器重載方式和方法重載差不多,隻需要構造器名相同,參數列表不同就可以瞭;

測試代碼:

public class ConstructorOverloadTest {
    String name;
    int age;

    // 默認構造器(無參構造器)
    ConstructorOverloadTest() {}
    // 含參構造器 重載版
    ConstructorOverloadTest(String myName, int myAge) {
        this.name = myName;
        this.age = myAge;
    }
    public static void main(String[] args) {
        // 調用無參構造器
        var p1 = new ConstructorOverloadTest();
        System.out.println("p1的初始化結果為:");
        System.out.println("姓名 :" + p1.name); 
        System.out.println("年齡:" + p1.age);
        // 調用有參構造器
        var p2 = new ConstructorOverloadTest("張三", 18);
        System.out.println("p2的初始化結果為:");
        System.out.println("姓名 :" + p2.name); 
        System.out.println("年齡:" + p2.age);
    }
}

輸出結果為:

p1的初始化結果為:
姓名 :null
年齡:0
p2的初始化結果為:
姓名 :張三
年齡:18

當然這裡隻寫瞭一個重載版本,還可以定義多個重載版本,這裡就不列舉瞭;我們隻需要能夠根據實際情況使用恰當的重載就可以瞭,不用都寫出來;

構造器間的相互調用

如果系統中有多個構造器,並且我們想要通過一個構造器A調用另一個構造器B,該怎麼辦?
可能有人會想到調用構造器肯定要創建一個對象啊,所以直接new一個不就可以瞭嘛; 但是我們通過一個構造器調用另一個構造器的目的就是為瞭簡化代碼的,這樣反而又多此一舉瞭;
如果不new一個新的對象,那麼我們可以通過 this引用 來調用相應的構造器;

還是不太明白?看看下面的代碼!
測試代碼如下:

public class ConstructorTest01 {
    public static void main(String[] args) {
        // 調用兩個參數的構造器
        Person p1 = new Person("張三", 18);
        System.out.println("兩個參數的構造器初始化結果為:");
        System.out.println("姓名:" + p1.name);
        System.out.println("身份證號:" + p1.idNum);
        System.out.println("年齡:" + p1.age);

        // 調用三個參數的構造器
        Person p2 = new Person("李四", "6666666", 20);
        System.out.println("三個參數的構造器初始化結果為:");
        System.out.println("姓名:" + p2.name);
        System.out.println("身份證號:" + p2.idNum);
        System.out.println("年齡:" + p2.age);
    }
}
class Person {
    String name;
    String idNum;
    int age;

    // 有兩個參數的構造器
    Person(String myName, int myAge) {
        this.name = myName;
        this.age = myAge;
    }
    // 有三個參數的構造器
    Person(String myName, String myIdNum, int myAge) {
        // 通過this調用兩個參數的構造器
        this(myName, myAge);
        this.idNum = myIdNum;
    }
}

輸出結果為:

兩個參數的構造器初始化結果為:
姓名:張三
身份證號:null
年齡:18
三個參數的構造器初始化結果為:
姓名:李四
身份證號:6666666
年齡:20

通過this調用有一點需要註意:
使用this調用另一個重載的構造器隻能在構造器中使用,且必須作為構造器執行體的第一條語句

可能有人會問:如果在有三個參數的構造器裡面不用this指針,而是直接把上一個構造器的代碼復制過來不行嗎?
當然可以,但是不建議;我們得知道為什麼要存在this這個調用構造器的方法,它不是無緣無故存在的;在軟件開發時有一個原則:不要把相同代碼重復寫兩次以上;因為一旦一個構造器內的初始代碼需要修改,那麼很有可能其他的構造器初始代碼也要跟著修改,如果構造版本多的話是非常麻煩的;而使用this恰恰可以避免這個問題,隻需要修改一個地方,其他幾個構造器就隨著更改瞭;這樣的代碼不僅更加簡潔,而且降低瞭維護成本;

子類構造器調用父類構造器

繼承有一個規則是:當繼承發生後,子類不會獲得父類的構造器;
但是子類的構造器可以通過一定方法區調用父類構造器,類似於通過this引用調用重載的構造器;
而子類構造器調用父類的構造器不用this關鍵字,這裡有一個新的關鍵字:super

super和this用法差不多,使用它就可以實現子類構造器調用父類的構造器;

看個代碼就明白瞭:
測試代碼:

class Person {
    String name;
    int age;
    // 父類的構造函數
    Person(String myName, int myAge) {
        this.name = myName;
        this.age = myAge;
    }
}
public class Kids extends Person{
    String school;
    // 子類的構造函數
    Kids(String myName, int myAge, String mySchool) {
        // 通過super來調用父類構造器初始化過程
        super(myName, myAge);
        this.school = mySchool;
    }
    public static void main(String[] args) {
        Kids k = new Kids("張三", 5, "奧特曼小學");
        System.out.println("name:" + k.name);
        System.out.println("age:" + k.age);
        System.out.println("school:" + k.school);
    }
}

輸出結果為:

name:張三
age:5
school:奧特曼小學

通過代碼可以看出來super確實和this非常像,無非就是super調用父類構造器,this調用同一個類的重載的構造器;
且使用super也需要註意:
super調用父類構造器也必須在子類構造器執行體的第一行,所以this和super不會同時出現;

構造器的調用順序

這裡先看一個代碼:

class Creature {
    Creature() {
        System.out.println("Creature的無參構造器的調用");
    }
}
class Person extends Creature {
    Person(String name) {
        System.out.println("Person的一個參數構造器的調用");
    }
    Person(String name, int age) {
        // this調用同一個類中重載的構造器
        this(name);
        System.out.println("Person的兩個參數構造器的調用");
    }
}
public class Kids02 extends Person {
    Kids02() {
        // 顯式調用父類的兩個參數的構造器
        super("張三", 18);
        System.out.println("Kids02的無參構造器的調用");
    }
    public static void main(String[] args) {
        // 創建一個Kids02對象
        new Kids02();
    }
}

這個代碼中,Person類繼承瞭Creature類,Kids02類繼承瞭Person類,Perosn類中又通過this調用同一個類中重載的構造器,
Kids02類中用super 顯式調用父類的兩個參數的構造器;
那麼輸出是什麼呢?到底先調用的是誰的構造器,最後調用的誰的構造器?

輸出如下:

Creature的無參構造器的調用
Person的一個參數構造器的調用
Person的兩個參數構造器的調用
Kids02的無參構造器的調用

通過這個代碼和結果,可以總結出來,父類構造器總在子類構造器之前執行,或者可以說:
創建任何對象總是從該類所在繼承樹最頂層類的構造器開始執行的,然後依次向下執行;
對於this和super也是一樣;

這個代碼好好理解一下,就會對構造器間的關系體會更深;

總結

對象的初始化離不開構造器,對構造器的學習真正需要的還是大量的練習,這些內容也是需要熟練掌握的;這關乎著你在實際開發應用過程中對整個代碼的影響和對象能否恰到好處的初始化;希望你能夠真正學會並應用到這些方法,且通過這篇文章能有所收獲!

ps:如果內容有問題歡迎討論!!

到此這篇關於Java中你真的會用Constructor構造器嗎之看完本篇你就真的會瞭的文章就介紹到這瞭,更多相關Java 構造器 Constructor內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: