如何编写无需强制类型转换的泛型方法返回自类型函数
问题:如何在Java自类型模式下避免强制类型转换?
说实话,我甚至不确定原标题是否合理,希望以下代码能说明问题。
package what.ever.you.like; import java.util.function.UnaryOperator; class SelfTypeTemplates { public static <SELF extends AbstractSelfType> UnaryOperator<SELF> simpleBound() { return self -> self; } public static <SELF extends AbstractSelfType<SELF>> UnaryOperator<SELF> boundWithGenericType() { return self -> self; } } class ConcreteSelfType extends AbstractSelfType<ConcreteSelfType> { public ConcreteSelfType() { super(ConcreteSelfType.class); } public ConcreteSelfType applySimpleBound() { // How to get rid of the type cast? return (ConcreteSelfType) SelfTypeTemplates.simpleBound().apply(this); } public ConcreteSelfType applyBoundWithGenericType() { // Compile error because `this` is ConcreteSelfType, but required is SELF return SelfTypeTemplates.boundWithGenericType().apply(this); } } class AbstractSelfType<SELF extends AbstractSelfType<SELF>> { protected final SELF myself; protected AbstractSelfType(final Class<?> type) { this.myself = (SELF) type.cast(this); } }
我的问题出在applySimpleBound()和applyBoundWithGenericType()这两个方法上:
- 前者可正常编译,但需要显式强制类型转换,这正是我想要消除的;
- 后者无法编译,因为
apply(this)需要SELF类型,但传入的是ConcreteSelfType。
请问如何定义SelfTypeTemplates中的方法签名,使其返回UnaryOperator<SELF>,让客户端代码(如ConcreteSelfType)调用返回函数的apply(this)时无需强制类型转换?我尝试过调整泛型的不同边界和返回类型,但未找到无需强转的可行方案。
解决方案
调整SelfTypeTemplates的方法签名
核心思路是给编译器提供足够的类型推导依据,让它能明确绑定SELF的具体类型。以下是两种可行方案:
方案1:传入Class对象作为类型标记
class SelfTypeTemplates { public static <SELF extends AbstractSelfType<SELF>> UnaryOperator<SELF> typedBound(Class<SELF> type) { return self -> self; } }
方案2:通过dummy参数推导类型
class SelfTypeTemplates { public static <SELF extends AbstractSelfType<SELF>> UnaryOperator<SELF> boundWithInference(SELF dummy) { return self -> self; } }
客户端代码调用示例
修改ConcreteSelfType中的方法,无需强制类型转换即可编译通过:
class ConcreteSelfType extends AbstractSelfType<ConcreteSelfType> { public ConcreteSelfType() { super(ConcreteSelfType.class); } public ConcreteSelfType applyTypedBound() { // 传入Class对象让编译器推导SELF类型 return SelfTypeTemplates.typedBound(ConcreteSelfType.class).apply(this); } public ConcreteSelfType applyBoundWithInference() { // 传入this作为dummy参数,编译器自动推导SELF类型 return SelfTypeTemplates.boundWithInference(this).apply(this); } }
原理说明
- 原
simpleBound()的泛型约束仅限定SELF extends AbstractSelfType,缺少递归自类型绑定,编译器无法确定返回的UnaryOperator的具体类型,因此必须强转。 - 原
boundWithGenericType()没有提供类型推导的入口,编译器无法将ConcreteSelfType与方法的SELF类型关联,导致参数类型不匹配。 - 调整后的方法通过显式类型标记或参数推导,让编译器明确
SELF的具体类型,既保证了类型安全,又消除了强制类型转换的需求。
额外优化:简化父类构造
可以通过反射优化AbstractSelfType,避免子类手动传入Class对象:
class AbstractSelfType<SELF extends AbstractSelfType<SELF>> { protected final SELF myself; @SuppressWarnings("unchecked") protected AbstractSelfType() { // 利用反射获取实际子类类型,省去手动传参 this.myself = (SELF) this; } }
内容的提问来源于stack exchange,提问作者Tob
相关产品推荐
相关产品推荐

