在我上一篇博文中,我介紹了一種建立策略類的方法,該方法充分利用了應用程式中存在的任何泛型元資料。在那篇文章的末尾,我展示了這段程式碼片段
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。那麼這在編譯後的類檔案中會變成什麼樣呢?我們有使用者提供的方法
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…