在我上一篇文章中,我介紹了一種建立策略類別的技術,該技術可以充分利用應用程式中存在的任何泛型元數據。 在該文章的末尾,我展示了以下程式碼片段:
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 編譯器會添加程式碼來建立並拋出它,方法是引入一個橋接方法。 橋接方法是編譯器將產生並添加到你的類別中的合成方法,以確保在面對泛型類型時的類型安全。
在上面顯示的情況中EntitlementCalculator.calculateEntitlement (權利計算器.計算權利)可以用任何與CorporateActionEvent (公司事件)類型相容的物件來呼叫。 然而,DividendEntitlementCalculator (股息權利計算器)僅接受與DividendCorporateActionEvent (股息公司事件)類型相容的物件,但是,由於你可以透過DividendEntitlementCalculator (股息權利計算器)通過EntitlementCalculator (權利計算器)介面呼叫,它也必須接受CorporateActionEvent (公司事件)。 那麼,這在編譯後的類別檔案中會轉換成什麼? 我們有使用者提供的函數
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…