![](/img/trans.png)
[英]Common generic method to handle operations on subclasses of java.lang.Number
[英]Java - Generic Number method signature bound to specific subclasses
我想编写一个将通用Number
用作参数并返回另一个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);
}
当然,如果它们是Integer
和Long
,我不能将N1
为N2
。 但是, Number
提供了doubleValue()
, intValue()
,...等方法,这些方法可以让我通过switch / case语句部分解决此问题。 那将限制我使用Number
类公开的xxxValue()
方法的返回类型,从而切断AtomicInteger
, AtomicLong
, BigInteger
和BigDecimal
。
对于我所想到的应用程序,这仍然是可以接受的,但是如果没有在switch / case块中使用default
语句来随意决定哪个xxxValue()
,则我的方法将无法正确处理Number
类的任何自定义或将来的官方扩展。 xxxValue()
方法来调用或引发异常(我想避免这种情况)。 我可以使用枚举按类型封装参数,但是恐怕我的代码将变得非常复杂和难以使用。
这个问题的答案提供了进一步的洞察力,即可以为两个参数声明一个通用类型(它并没有强制要求两个参数实际上在运行时都属于同一类型),在这里肯定值得一提。
我想要实现的是:
Number
参数的方法,可能会更多带有不同数量参数的方法(例如,带有两个参数的方法,带有三个参数的方法),但在每个参数中仍然是通用的。 Number
扩展(例如Integer
, Double
)。 (Double, Integer)
, (Double, Double)
, (Integer, Double)
, (Integer, Integer)
。 我不想定义多个具有不同签名的方法。 即使将返回类型固定为例如Double
,随着添加更多参数和类型,方法的数量也会激增。
当然,我可能总是对每种方法都采用特定的特定实现,因为我可能不需要每种类型的所有可能组合。 我仍然希望我的设计在执行这些类型约束时足够灵活。
这是我最好的解决方法,它调用接受String作为参数的构造函数,并在失败时返回null(已编辑以删除printStackTrace并删除一个不必要的分支)
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.