我们可以将bar 中的foo 调用替换为对应的BiFunction 调用。因此,对于所有重载的 foo 方法,必须定义一个 BiFunction。
private static final Map<Class<?>, BiFunction<?, Integer, TypeR>> FOO = Map.of(
TypeA.class, (first, second) -> foo((TypeA) first, second),
TypeB.class, (first, second) -> foo((TypeB) first, second),
TypeC.class, (first, second) -> foo((TypeC) first, second));
但是对于每个重载的foo 映射,只需编写一行,而每个重载的bar 方法如果按照问题中的方式编写则需要四行。
现在我们可以将bar 设为通用。但是下面的方法不起作用,因为返回的BiFunction 有一个未绑定的通配符作为第一个类型参数。
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return FOO.get(first.getClass()).apply(first, second);
}
我们需要将FOO 声明为Map<Class<T>, BiFunction<T, Integer, TypeR>>,但这是不可能的。为了解决这个问题,我们定义了一个带有类型参数T 的方法,它应该建立缺少的类型相等性。但这不是免费的。这是以强制转换导致的警告为代价的:
private static <T> BiFunction<T, Integer, TypeR> fooOf(Object o) {
return (BiFunction<T, Integer, TypeR>) FOO.get(o.getClass());
}
现在我们可以在bar中使用这个方法了:
<T> TypeR bar(T first, int baz) {
int second = someCalculation(baz);
return fooOf(first).apply(first, second);
}
这类似于instanceof 方法,但将类型区别从方法bar 替换为Map FOO。如果有除bar以外的其他方法也需要以类似方式调用foo,则不再编码类型区分。 FOO 和 fooOf 可以重复使用。如果库发生变化并引入了额外的重载TypeR foo(TypeD first, int second),则只需添加一行即可更新FOO。
这种方法要求first 不是null。