Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java-绑定到特定子类的泛型数字方法签名_Java_Generics_Enums - Fatal编程技术网

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
  • 参数可以有多种组合,可能是
    (双精度,整数)
    (双精度,双精度)
    (整数,双精度)
    (整数,整数)
    中的任意一种
我不想定义具有不同签名的多个方法。即使在修复返回类型(例如,to
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;
}