Java構造器和初始化塊
來源: 流浪舟 https://www.maliaoblog.cn/2020/0924
公衆号: 菜雞幹Java
文章目錄
-
-
- Java構造器和初始化塊
-
- 構造器的作用
- 構造器重載
- 調用父類構造器
- 初始化塊
-
- 初始化塊和構造器
- 靜态初始化塊
-
構造器是一個特殊的方法,但定義構造器和普通方法沒什麼太大差別,該有的都有。不過為了區分還是看看不一樣的地方。
- 方法名:構造器方法名需要和類名一樣
- 傳回值:構造器不定義傳回值,也不用傳回
,但是它會傳回一個對象(隐式的)void
- 修飾符:一般設為
權限,可以被其他方法調用public
- 不是靜态的:構造器方法不用
修飾static
在定義一個類時,沒有寫構造器,系統将預設提供一個無參構造器。構造器是建立一個對象的途徑之一。上面的第四點很少有書提到,但是我們也很少見到用
static
修飾的構造器—靜态構造器。這裡先講一個知識點:在
static
修飾的方法中如果使用
this
關鍵字,則關鍵字無法指向對象。而通路非靜态成員是隐式通路,在沒有重名下,省略了
this
關鍵字,是以靜态成員是無法通路非靜态成員。回到
static
修飾,構造器如果用靜态的,則不能通路非靜态成員,而構造器是用來初始化成員變量的,那怎麼初始化,怎麼建立對象?最後還要傳回對象。其次,建立對象會比較麻煩,
new
類名加構造器是不可想象的!
既然構造器不用類名加構造器通路,開始又沒有執行個體對象,那如何通路呢?是以,Java提供關鍵字
new
來調用構造器,是以在構造器中關鍵字
this
表示構造器正在初始化的對象,當然大多數情況下可以省略,除了構造器中有一個重名的局部變量的情況下。
public MyConstructor(){
int son = 0;
this.son = 6;//構造器會把所有對象的son屬性初始化為6
}
構造器的作用
主要作用還是為了
初始化
,預設初始化把所有數字基本類型執行個體變量設為0,布爾類型為
false
,引用類型為
null
,如果想改變一下,可以在構造器中定義。
public MyConstructor(String name,int age){
this.name = name;//傳入兩參數
this.age = age;
}
需要注意的是構造器不是全權負責建立對象,在執行構造器之前,系統已為對象配置設定了記憶體,結束後構造器傳回對象,讓引用指向該對象。
構造器重載
如果想保留無參構造器,可以提供多個構造器,形成構造器重載。重載後,構造器的參數清單是不一樣的,這樣能利用不同的構造器建立不同的對象。如果包含多個構造器,其中一個構造器代碼包含另一個,如下。這種情況是可以有簡潔的代碼代替的,但構造器不能直接被調用,用
new
關鍵字又會建立一個對象,則使用
this
關鍵字很好解決,
this
調用另一個重載的構造器。
此種方法僅限在構造器中使用
public class dog{
public String name;
public int age;
public int weight;
public dog(){}
public dog(String name,int age){
this.name = name;
this.age = age;
}
public dog(String name,int age,int weight){
this(name,age);//調用另一個構造器的初始化代碼
//其實還可以用以下代碼代替,但是不建議
//this.name = name;
//this.age = age;
this.weight = weight;
}
}
調用父類構造器
子類繼承父類不會獲得父類的構造器,但子類構造器可以調用父類構造器的初始化代碼,類似上面的調用另一個重載構造器。在一個構造器中調用另一個構造器用
this
完成,在子類構造器中調用父類構造器則用
super
完成。
super
調用必須出現在子類構造器的第一行,因為Java設計子類執行構造器必須先調用父類構造器,是以它是第一行,然後,然後就沒
this
啥事了,因為剛才講了,再
this
調用又要執行父類構造器。
this
與
super
不能同時使用!
子類繼承了父類的屬性和方法,是以在先初始化父類的屬性和方法,這樣子類才可以初始化自己特有的,因為java中不允許調用沒有初始化的成員。
this
就是調用本類的其他構造函數,在其他構造函數中也有預設的super(),或者自定義了帶參的
super
,這樣就初始化了父類的成員了,是以寫了
this
的構造函數不能再寫
super
了,因為執行個體化一個對象運作兩次
super
是不安全的。
this
放在第一行,也是因為要先初始化父類和this代表的構造函數先,因為目前構造函數可能用到那些成員,是以那些成員得要先初始化
不管是否使用
super
調用父類構造器,子類總會調用父類構造器一次,有以下情況:
- 子類構造器使用
顯式調用父類構造器super
- 子類構造器使用
調用重載構造器,執行前重載構造器先會隐式調用父類構造器this
- 子類構造器既無
調用,也沒有super
調用,則系統預設調用父類無參構造器this
建立任何對象時,總是從該類所在繼承樹最頂層類的構造器開始執行,然後往下執行到本類構造器。如果父類構造器還調用了重載構造器,那就會依次執行多個構造器。
初始化塊
跟構造器作用差不多,初始化塊也可以進行對象初始化,它比構造器先執行。它也是類的一種成員,修飾符隻能用
static
修飾,被修飾稱為靜态初始化塊,也可以不修飾。
{
a = 6;
}
int a = 9;
public test(){
System.out.println(new MyInstance().a);
}//輸出9,執行個體變量值為9
類和對象無法調用初始化塊,初始化塊隻在建立對象時隐式執行,而且在構造器之前執行。此外,普通初始化塊、聲明執行個體變量指定預設值,都可認為是對象的初始化塊,執行順序和排列順序一樣。
當建立一個對象時,系統先為對象的所有執行個體變量配置設定記憶體,接着程式開始對執行個體變量初始化,初始化順序是:先執行初始化塊或聲明執行個體變量時指定初始值,再執行構造器中的初始值。
初始化塊和構造器
與構造器不同,初始化塊是一段固定的代碼,不接收參數,是以初始化塊對同一個類的所有對象的初始化處理是一樣的。是以就這種特點,我們可以利用來初始化相同一段值。構造器中相同一段代碼可以提煉出相同初始化塊,簡化了程式,提高了複用性和可維護性。
實際上在編譯Java塊後,初始化塊會消失,初始化塊的代碼會被“還原”到構造器中,且位于構造器代碼前面!
與構造器類似,建立一個Java對象,不僅會執行該類的普通初始化塊和構造器,而且系統會從
Object
類開始執行,往下執行父類,然後才到該類的初始化塊和構造器。如果希望類加載後對整個類進行初始化操作,例如把類變量初始化一下,則需要用靜态初始化塊。
靜态初始化塊
也叫類初始化塊,屬于類的靜态成員,同樣需要遵循
靜态成員不能通路非靜态成員的規則
。普通初始化塊負責對對象執行初始化,類初始化塊則負責對類進行初始化。類初始化時,系統執行靜态初始化塊。靜态初始化塊是類相關的,系統将在類初始化階段執行靜态初始化塊,而不是建立對象時才執行,是以靜态初始化塊總是比普通初始化塊先執行。靜态初始化塊不能對執行個體變量進行初始化處理。
與普通初始化塊類似,系統執行類的靜态初始化塊不僅會執行本類的靜态初始化塊,還會從源頭類
Object
類開始執行,道理一樣。類初始化後,才能使用這個類,然後才能建立對象。一旦類初始化成功,該類在JVM中一直存在,是以建立執行個體時,無須對類進行初始化。建立執行個體時,都需要先執行頂層父類的初始化塊、構造器,然後執行父類的初始化塊、構造器,然後執行本類的初始化塊和構造器。
靜态初始化塊->普通初始化塊->構造器
Java系統加載并初始化某個類時,總是保證該類的所有父類全部加載和初始化!靜态初始化塊和聲明靜态變量時所指定的初始值都是該類的初始化代碼。JVM第一次主動調用某個類,系統會在類準備階段為該類所有靜态成員配置設定記憶體,初始化階段負責初始化。
public class Test{
static { //(1)
a = 6;
}
static int a = 9;//(2)
public static void main(String[] args){
System.out.println(Test.a);
}//輸出9,如果調換(1)(2)則為6
}