在我的上一篇文章中,我介绍了一种创建策略类的方法,该方法充分利用了应用程序中存在的任何泛型元数据。在那篇文章的末尾,我展示了以下代码片段
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。那么这在编译后的 class 文件中意味着什么呢?我们有用户提供的方法
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…