Java 25 中靈活的建構子主體
1.概述
在本教程中,我們將介紹在 Java 25 中編寫建構函式時可用的新選項。在 JEP 513 實作之後,我們現在可以更好地控制建構函式主體的順序,從而提供增強程式碼安全性和效率的選項。
2. Java 25 之前
在早期版本的 Java 中,物件的建構子必須遵循嚴格的順序。任何建構子的第一行都必須是super(…)
、 this(…),
或其他建構子呼叫。這強制執行了先呼叫超類別建構子再呼叫子類別建構子的規則。另外值得注意的是,如果我們沒有明確地編寫對super()
或類似方法的調用,編譯器會為我們添加一個。
這導致了安全的物件構建,但也限制了我們在程式碼中添加潛在有用的技術。
3. 代碼設定
讓我們設定一些物件來測試新功能。首先,我們可以創建一個Coffee
超類,其中包含兩個字段,分別代表咖啡的主要成分:牛奶和水:
public class Coffee {
int water;
int milk;
public Coffee(int water, int milk) {
this.water = water;
this.milk = milk;
}
public int getTotalVolume() {
return water + milk;
}
}
所以,這裡沒有什麼意外:兩個字段、一個構造函數和一個小方法來告訴我們Coffee's
總量。
現在,讓我們擴展一下飲料範圍,加入一款SmallCoffee
。目前, SmallCoffee
與標準Coffee
相同,但它帶有一個配料:
public class SmallCoffee extends Coffee {
String topping;
public SmallCoffee(int water, int milk, String topping) {
super(water, milk);
this.topping = topping;
}
}
我們新增了一個名為 topping 的新String
欄位。在建構函數中,我們呼叫了超類別的建構函數,並傳入了所需的字段,然後實例化了新的 topping 字段。
一切都很好。但是,如果我們想對SmallCoffee
進行最大容量限製或其他限制,該怎麼辦?我們必須在呼叫超類別建構函數後進行檢查。在下一節中,我們將研究如何提前進行檢查,以確保物件的格式正確且有效率。
4. 序言檢查
從 Java 25 開始,我們可以選擇在建構函式中加入 Prologue。 Prologue是指在呼叫super(…)
或this(…).
讓我們使用序言來為我們的SmallCoffee
添加一個檢查,以確保我們不會超過小杯子所能容納的最大容量:
public SmallCoffee(int water, int milk, String topping) {
int maxCupVolume = 100;
int totalVolume = water + milk;
if(totalVolume > maxCupVolume) {
throw new IllegalArgumentException();
}
super(water, milk);
this.topping = topping;
}
透過這種實現,我們預先檢查物件是否有效,如果無效,則會立即失敗。
在 Java 25 之前,我們必須在呼叫super(water, milk)
之後執行此檢查。如果總容量過大,這就會浪費建構超類的精力。
5. 序言實例
使用 Prologues,我們可以實例化任何尚未實例化的類別變數。我們可以按照常規方式進行操作:
String topping;
public SmallCoffee(int water, int milk, String topping) {
this.topping = topping;
super(water, milk);
}
現在我們在建構超類別之前實例化頂級欄位。
讓我們寫一個簡短的測試來確認這一切都能按預期編譯和工作:
@Test
public void test() {
SmallCoffee smallCoffee = new SmallCoffee(30,40, "none");
assertEquals(70, smallCoffee.getTotalVolume());
}
測試透過顯示我們的 Prologue 檢查和實例化過程正確無誤。這也證明我們呼叫了超類別的建構函數,並且傳回的結果是一個格式正確的SmallCoffee
,並且液體體積符合預期。
6. 限制
在建構函數的序言部分,我們可以做的事情有一些限制。主要限制是,序言部分的程式碼不能使用或引用目前正在建立的物件。現在,我們將分析一些不允許的例子。
6.1. 使用實例方法
首先,我們不能在序言中使用物件自己的方法:
public SmallCoffee(int water, int milk, String topping) {
addRandomTopping();
super(water, milk);
}
private void addRandomTopping() {...}
這是不允許的,因為我們試圖從在呼叫super()
之前建立的物件中呼叫一個方法。在呼叫 super() 之後呼叫就可以了。
6.2. 使用實例字段
其次,我們不能在序言中引用物件的欄位:
String name;
public SmallCoffee(int water, int milk, String topping) {
String nameWithExclamationMark = name + "!";
super(water, milk);
}
這會失敗,因為我們嘗試在呼叫super()
之前使用name
欄位。
類似地,我們不能為已經初始化的類別字段賦值:
String name = "Flat white";
public SmallCoffee(int water, int milk, String topping) {
name = "Espresso";
super(water, milk);
}
當我們嘗試將SmallCoffee
重新命名為Espresso
時,失敗了。在呼叫超類別建構子後重新分配變數則一切正常。
7. 結論
在本教程中,我們了解到,從 Java 25 開始,我們可以在建構函式中加入序言。序言是指在呼叫下一個建構函數之前執行的任何程式碼。
我們在序言中進行了檢查,確保物件內部保持了正確的規範。此外,由於類別欄位尚未初始化,因此我們對其進行了實例化。
序言限制了我們對其的更多操作。主要是,它阻止我們在創建職業之前使用職業特性。
與往常一樣,範例的完整程式碼可在 GitHub 上找到。