1. 程式人生 > >java 構造器(構造方法)使用詳細說明

java 構造器(構造方法)使用詳細說明

# 知識點 - **什麼是構造器** 構造器通常也叫構造方法、建構函式,構造器在每個專案中幾乎無處不在。當你new一個物件時,就會呼叫構造器。構造器格式如下: ```java [修飾符,比如public] 類名 (引數列表,可以沒有引數){ //這裡不能有return } ``` - **預設構造器** 如果沒有定義構造器,則會預設一個無參構造器,這就是為什麼你定義了一個物件,比如 People,沒有定義任何構造器卻可以new這個物件,比如 new People() 。如果自定義了構造器,則會覆蓋預設構造器。 - **如何禁止物件被外部建立** 一些特殊需求,不希望定義的物件被外部建立(典型的就是單例了),那直接將構造器的修飾符改為 private 即可。這樣就不能在外部通過new來建立這個物件了。 - **構造器過載** 與普通方法一樣,構造器也支援過載。一個物件中是可以支援同時定義多個構造器,通過不同的引數列表來實現過載。經常看到程式碼中new一個物件時,有時傳入引數,有時又可以不用傳。比如:new People()跟new People("張三"),這裡就是過載了。 - **構造器的繼承** 子類構造器會預設呼叫父類無參構造器,如果父類沒有無參構造器,則必須在子類構造器的第一行通過 super關鍵字指定呼叫父類的哪個構造器,**具體看下文例子**。final類是不允許被繼承的,編譯器會報錯。很好理解,由於final修飾符指的是不允許被修改,而繼承中,子類是可以修改父類的,這裡就產生衝突了,所以final類是不允許被繼承的。 - **構造器、靜態程式碼塊、構造程式碼塊的執行順序,詳見下文例項** * 無繼承的情況下的執行順序 **靜態程式碼塊**:只在程式啟動後執行一次,優先順序最高 **構造程式碼塊**:任何一個構造器被呼叫的時候,都會先執行構造程式碼塊,優先順序低於靜態程式碼塊 **構造器**:優先順序低於構造程式碼塊 _總結一下優先順序:靜態程式碼塊 > 構造程式碼塊 > 構造器_ * 有繼承的情況下的執行順序: **父類靜態程式碼塊**:只在程式啟動後執行一次,優先順序最高 **子類靜態程式碼塊**:只在程式啟動後執行一次,優先順序低於父類靜態程式碼塊 **父類構造程式碼塊**:父類任何一個構造器被呼叫的時候,都會執行一次,優先順序低於子類靜態程式碼塊 **父類構造器**:優先順序低於父類構造程式碼 **子類構造程式碼塊**:子類任何一個構造器被呼叫的時候,都會執行一次,優先順序低於父類構造器 **子類構造器**:優先順序低於子類構造程式碼塊 _總結一下優先順序:父類靜態程式碼塊 > 子類靜態程式碼塊 > 父類構造程式碼塊 > 父類構造器 > 子類構造程式碼塊 > 子類構造器_ # 例項 ## 1.預設構造器 新建一個類,不提供任何構造器,編譯器會預設提供一個無參構造器,這就是為什麼沒定義任何構造器,卻可以new 某個物件() ```java public class People { } ``` 以上這個People類,可以直接通過 new People()來例項化。 ## 2. 禁止物件被外部建立 如果不希望People在外部通過new People()來例項化,只需要將構造器定義為private ```java public class People { private People(){ } } ``` ## 3.構造器過載 過載可以簡單理解為:同個方法名,不同的引數列表。如果希望People能在外部通過new People() 或 new People("字串") 來例項化,則通過以下程式碼即可 ```java public class People { //通過new People()呼叫 public People(){ } //通過new People("字串") 呼叫 public People(String str){ } } ``` ## 4.構造器的繼承 定義父類構造器,由於該構造器自定義了一個帶參構造器,覆蓋了預設的無參構造器,所以不能直接 new SuperClass() 呼叫了,除非再定義一個無參構造器 ```java /** * 父類構造器 */ public class SuperClass { /** * 自定義帶參構造器 */ public SuperClass(String str){ System.out.println("父類的帶參構造方法,引數為:" + str); } } ``` 定義子類構造器,繼承SuperClass,由於SuperClass沒有無參構造器,所以必須在子類構造器中通過 super("字串")來呼叫,否則編譯器會報錯 ```java /** * 子類構造器 */ public class SubClass extends SuperClass { /** * 無參構造器 */ public SubClass(){ //由於SuperClass沒有無參構造器,所以必須在子類構造器中通過 super("字串")來呼叫,否則編譯器會報錯。 //如果沒定義該句,則編譯器會預設呼叫 super() super(""); } /** * 帶參構造器 */ public SubClass(String subStr){ //由於SuperClass沒有無參構造器,所以必須在子類構造器中通過 super("字串")來呼叫,否則編譯器會報錯。 //如果沒定義該句,則編譯器會預設呼叫 super() super(subStr); } } ``` ## 5. 構造器、靜態程式碼塊、構造程式碼塊的執行順序 ### 5.1 無繼承的情況 ```java public class People { static { System.out.println("靜態程式碼塊,程式啟動後執行,只會執行一次"); } /** * 預設的無參構造器 */ public People(){ System.out.println("預設構造器"); } /** * 構造器過載,自定義一個帶參構造器 * @param str */ public People(String str){ System.out.println("帶參構造器,引數:" + str); } { System.out.println("構造程式碼塊,每次呼叫構造方法都會執行一次"); } } ``` 例項化People ```java public static void main(String[] args){ System.out.println("--------------people----------------"); People people = new People(); System.out.println("--------------people1----------------"); People people1 = new People("張三"); } ``` 執行以上程式碼,輸出: ```java --------------people---------------- 靜態程式碼塊,程式啟動後執行,只會執行一次 構造程式碼塊,每次呼叫構造方法都會執行一次 預設構造器 --------------people1---------------- 構造程式碼塊,每次呼叫構造方法都會執行一次 帶參構造器,引數:張三 ``` ### 5.2 有繼承的情況 定義父類SuperClass ```java /** * 父類構造器 */ public class SuperClass { { System.out.println("父類構造程式碼塊,每次呼叫構造方法都會執行的"); } /** * 父類無參構造方法 */ public SuperClass(){ System.out.println("父類的預設構造方法"); } /** * 過載,自定義父類帶參構造方法 * @param str */ public SuperClass(String str){ System.out.println("父類的帶參構造方法,引數為:" + str); } static { System.out.println("父類的靜態程式碼塊,程式啟動後執行,只會執行一次"); } } ``` 定義子類SubClass,繼承SuperClass ```java /** * 子類構造器,繼承SuperClass */ public class SubClass extends SuperClass { static { System.out.println("子類的靜態程式碼塊,程式啟動後執行,只會執行一次,先執行父類的,再執行子類的"); } { System.out.println("子類構造程式碼塊,每次呼叫構造方法都會執行的"); } /** * 無參構造器 */ public SubClass(){ //這裡沒有指定呼叫父類哪個構造器,會預設呼叫 super(),呼叫父類的無參構造器public SuperClass() } /** * 過載構造器,多傳兩個引數 * @param str * @param str1 */ public SubClass(String str,String str1){ //必須寫在構造器第一行,呼叫父類構造器 public SuperClass(String str) super(str); System.out.println("子類帶參構造器:" + str1); } } ``` 例項化SubClass ```java public static void main(String[] args){ System.out.println("--------------subClass1----------------"); SubClass subClass1 = new SubClass(); System.out.println("--------------subClass2----------------"); SubClass subClass2 = new SubClass("子類第一個引數","子類第二個引數"); } ``` 執行以上程式碼,輸出: ```java --------------subClass1---------------- 父類的靜態程式碼塊,程式啟動後執行,只會執行一次 子類的靜態程式碼塊,程式啟動後執行,只會執行一次,先執行父類的,再執行子類的 父類構造程式碼塊,每次呼叫構造方法都會執行的 父類的預設構造方法 子類構造程式碼塊,每次呼叫構造方法都會執行的 --------------subClass2---------------- 父類構造程式碼塊,每次呼叫構造方法都會執行的 父類的帶參構造方法,引數為:子類第一個引數 子類構造程式碼塊,每次呼叫構造方法都會執行的 子類帶參構造器:子類第二個引數 ``` # 原始碼獲取 以上示例都可以通過[我的GitHub](https://github.com/simonxie/javase-demo)獲取完整的程式碼,[點選獲取](https://github.com/simonxie/javase-demo/tree/master/src/main/java/com/simon/constru