在我上一篇文章中,我介绍了一种创建策略类的方法,该方法充分利用了应用程序中存在的任何泛型元数据。在那篇文章的末尾,我展示了这段代码片段
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…