在我上一篇文章中,我介紹了一種建立策略類的方法,該方法充分利用了應用程式中存在的任何泛型元資料。在那篇文章的末尾,我展示了這段程式碼片段
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…