java 構造器(構造方法)使用詳細說明
阿新 • • 發佈:2020-03-08
# 知識點
- **什麼是構造器**
構造器通常也叫構造方法、建構函式,構造器在每個專案中幾乎無處不在。當你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