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