Java-绑定到特定子类的泛型数字方法签名
我想写一个方法,它将一个泛型的Java-绑定到特定子类的泛型数字方法签名,java,generics,enums,Java,Generics,Enums,我想写一个方法,它将一个泛型的Number作为参数,并返回另一个Number,其类型可能与第一个不同,并作为第二个参数传递。大概是这样的: public <N1 extends Number, N2 extends Number> N2 op(N1 num, Class<N2> retType) { //Sample operation, where type conflicts arise. return retType.cast(num + 3); }
Number
作为参数,并返回另一个Number
,其类型可能与第一个不同,并作为第二个参数传递。大概是这样的:
public <N1 extends Number, N2 extends Number> N2 op(N1 num, Class<N2> retType) {
//Sample operation, where type conflicts arise.
return retType.cast(num + 3);
}
public N2 op(N1个,类类型){
//出现类型冲突的示例操作。
返回retType.cast(num+3);
}
当然,我不能把N1
转换成N2
,如果它们是,比如说,Integer
和Long
。但是,Number
提供了doubleValue()
,intValue()
,方法,这些方法允许我使用switch/case语句部分解决问题。这将限制我使用Number
类公开的xxxValue()
方法的返回类型,从而切断AtomicInteger
、AtomicLong
、BigInteger
和BigDecimal
对于我心目中的应用程序来说,这仍然是可以接受的,但是如果没有switch/case块中的default
语句,我的方法将无法正确处理Number
类的任何自定义或将来的官方扩展,该语句应该任意决定调用哪个xxxValue()
方法,或者抛出一个异常(我希望避免)。我可以使用枚举按类型封装参数,但我担心我的代码会变得太复杂,难以使用
对的回答提供了关于为两个参数声明单个泛型类型的更深入的见解(它不强制要求两个参数在运行时实际上是同一类型的),这在这里确实值得一提
我想要实现的是:
- 声明具有一些泛型(广义上)参数的方法,可能有更多具有不同数量参数的方法(例如,具有两个参数的方法,具有三个参数的方法),但在每个参数中仍然是泛型的
- 参数必须限制为一些众所周知的扩展名
(例如Number
,Integer
)Double
- 参数可以有多种组合,可能是
、(双精度,整数)
、(双精度,双精度)
、(整数,双精度)
中的任意一种(整数,整数)
Double
)时,随着更多参数和类型的添加,方法的数量也会激增
当然,对于每个方法,我可能总是求助于特定的、特别的实现,因为我可能不需要所有可能的类型组合。我仍然希望我的设计在执行这些类型约束时足够灵活。这是我最好的解决方法,它调用接受字符串作为参数的构造函数,如果失败则返回null(编辑以删除printStackTrace并删除一个不必要的分支)
publicstaticr op(Number num,Class retType){
BigDecimal三=BigDecimal.valueOf(3);
BigDecimal bdNum=新的BigDecimal(num.toString());
//加三
BigDecimal bdResult=bdNum.add(三);
字符串strResult=bdResult.toString();
构造函数[]cons=retType.getDeclaredConstructors();
对于(构造函数con:cons){
if(con.getParameterCount()==1){
if(con.getGenericParameterTypes()[0]==String.class){
试一试{
返回(R)con.newInstance(strResult);
}catch(实例化异常|非法访问异常| NumberFormatException e){
}捕获(调用TargetException e){
//如果在此处,则小数位中的任何一位都会导致问题
//转换为整型时,
//或者该值对于目标类型太大
//因此,让我们尝试通过截断小数点来删除小数点。
strResult=bdResult.toBigInteger().toString();
试一试{
返回(R)con.newInstance(strResult);
}catch(NumberFormatException | IllegalacessException | InstanceionException | InvocationTargetException e1){
}
}
//如果在这里,则最有可能的积分类型太大
//就像把3000000000放进一个整数
//当可能的最大整数为2147483647时
}
//如果在这里,则没有带1个字符串参数的构造函数
}
}
返回null;
}
“参数必须限制在一些众所周知的数字扩展上”——这将是一种联合类型,Java没有。关于一些想法,请参见和,但我认为它们中的任何一个都不适用于这样的方法。不适用于AtomicInteger、AtomicLong,但适用于所有其他数字类型。恐怕,对于我心目中的用途来说,使用起来有点太繁重了。因为事实上我不需要BigInteger和BigDecimal,我想我可以求助于需要并返回相同类型参数的接口,比如double op(double par1,double par2){…}
,毕竟它只是四种用于float、double、int和long的方法。我认为这可能是一个公平的妥协与模板模式也许。。。
public static <R extends Number> R op(Number num, Class<R> retType) {
BigDecimal three = BigDecimal.valueOf(3);
BigDecimal bdNum = new BigDecimal(num.toString());
//add three
BigDecimal bdResult = bdNum.add(three);
String strResult = bdResult.toString();
Constructor[] cons = retType.getDeclaredConstructors();
for (Constructor con: cons) {
if (con.getParameterCount() == 1) {
if (con.getGenericParameterTypes()[0] == String.class) {
try {
return (R)con.newInstance(strResult);
} catch (InstantiationException | IllegalAccessException | NumberFormatException e) {
} catch (InvocationTargetException e) {
//if here then either the decimal place is causing a problem
// when converting to integral type,
// or the value is too large for the target type
// so let's try to remove the decimal point by truncating it.
strResult = bdResult.toBigInteger().toString();
try {
return (R)con.newInstance(strResult);
} catch (NumberFormatException | IllegalAccessException | InstantiationException | InvocationTargetException e1) {
}
}
//if here, then the most likely the integral type is too large
//like trying to put 3,000,000,000 into an int
// when largest int possible is 2,147,483,647
}
//if here, then no constructors with 1 String parameter
}
}
return null;
}