Java泛型接口如何限制类型参数仅为Integer或Float
Java 原生语法没有直接支持「限定泛型参数为指定的多个不相关类型」的特性,因为Integer和Float共同的父类Number还包含Long、Double等其他子类,直接使用<T extends Number>无法满足范围限制要求,可通过以下两种方案实现需求:
方案1:Java 17+ 密封接口实现编译期强校验
由于Integer、Float都是final类无法实现自定义接口,我们可以先定义密封的包装接口,仅允许对应两种类型的包装类实现,再将其作为泛型上界:
// 密封接口,仅允许IntOperand、FloatOperand作为实现类 public sealed interface Operand permits IntOperand, FloatOperand { Number getValue(); } // Integer包装实现 public record IntOperand(Integer value) implements Operand { @Override public Integer getValue() { return value; } } // Float包装实现 public record FloatOperand(Float value) implements Operand { @Override public Float getValue() { return value; } }
调整原接口的泛型上界即可完成限制:
public interface Math<T extends Operand> { T add(T t, T r); }
该方案所有校验都在编译期完成,没有运行时开销,抽象方法不需要硬编码任何类型,后续需要新增支持的类型时仅需修改permits列表并新增对应包装实现即可。
方案2:上界限定+工厂校验,兼容低版本Java
如果你的项目使用Java 16及以下版本,可以将泛型上界限定为Number,通过静态工厂方法在实例化时做类型校验,配合Javadoc提示开发者合法的泛型范围:
/** * 泛型参数T仅支持Integer、Float两种类型 * @param <T> 运算数值类型,必须为Integer或Float */ public interface Math<T extends Number> { T add(T t, T r); // 静态工厂方法,实例化时校验类型合法性 static <T extends Number> Math<T> getInstance(Class<T> clazz) { if (clazz != Integer.class && clazz != Float.class) { throw new IllegalArgumentException("仅支持Integer、Float作为泛型参数"); } if (clazz == Integer.class) { return (Math<T>) new IntegerMathImpl(); } else { return (Math<T>) new FloatMathImpl(); } } } // Integer运算实现类 class IntegerMathImpl implements Math<Integer> { @Override public Integer add(Integer t, Integer r) { return t + r; } } // Float运算实现类 class FloatMathImpl implements Math<Float> { @Override public Float add(Float t, Float r) { return t + r; } }
该方案不需要修改原有业务的数值入参类型,对业务代码侵入性极低。
内容的提问来源于stack exchange,提问作者cc604
相关产品推荐
相关产品推荐

