在我的上一篇文章中,我介紹了一種建立策略類的方法,該方法充分利用了應用程式中存在的任何泛型元資料。在那篇文章的末尾,我展示了以下程式碼片段
EntitlementCalculator calculator = new DividendEntitlementCalculator();
calculator.calculateEntitlement(new MergerCorporateActionEvent());
您會記得DividendEntitlementCalculator被定義為
public class DividendEntitlementCalculator implements EntitlementCalculator<DividendCorporateActionEvent> {
public void calculateEntitlement(DividendCorporateActionEvent event) {
}
}
因此,傳遞一個MergerCorporateActionEvent的例項到calculateEntitlement方法中是不正確的。DividendEntitlementCalculator類。然而,正如我在上一篇文章中提到的,那段程式碼可以編譯。為什麼?嗯,EntitlementCalculator.calculateEntitlement()被定義為接受任何繼承自CorporateActionEvent的型別,所以它應該編譯。那麼在這種情況下,執行時會發生什麼,Java 如何強制執行型別安全呢?嗯,正如你可能想象的那樣,執行這段程式碼會給你一個ClassCastException說你不能將MergerCorporateActionEvent轉換為DividendCoporateActionEvent。透過這種方式,Java 可以為你的應用程式強制執行型別安全——絕不可能將MergerCorporateActionEvent潛入到預期接受DividendCorporateActionEvent的方法中。
這裡真正的問題是:“那個ClassCastException從何而來?”答案很簡單——Java 編譯器透過引入橋接方法(bridge method),在適當的時候添加了建立和丟擲它的程式碼。橋接方法是編譯器生成並新增到你的類中的合成方法,以確保在面對泛型型別時的型別安全。
在上面展示的例子中EntitlementCalculator.calculateEntitlement可以用任何與CorporateActionEvent型別相容的物件呼叫。然而,DividendEntitlementCalculator只接受與DividendCorporateActionEvent型別相容的物件,但是,由於你可以透過DividendEntitlementCalculator呼叫EntitlementCalculator介面,它也必須接受CorporateActionEvent。那麼這在編譯後的 class 檔案中意味著什麼呢?我們有使用者提供的方法
public void calculateEntitlement(DividendCorporateActionEvent event) {
System.out.println(event);
}
這會轉換為以下的位元組碼
public void calculateEntitlement(bigbank.DividendCorporateActionEvent);
Code:
Stack=2, Locals=2, Args_size=2
0: getstatic #2; //Field java…