我想在这里过于聪明吗?
private static <T extends Number> Long extractLong(T value) {
if ( value < Long.MIN_VALUE || value > Long.MAX_VALUE ) { // <= compile error
throw new NumberFormatException("Conversion from " + value + " to Long will overflow");
}
return value.longValue();
}
Run Code Online (Sandbox Code Playgroud)
这会产生编译错误:
对于参数类型T,long,运算符>未定义
但是,如果我明确地执行该函数,它将编译:
private static Long extractLong(Long value) {
if ( value < Long.MIN_VALUE || value > Long.MAX_VALUE ) {
throw new NumberFormatException("Conversion from " + value + " to Long will overflow");
}
return value.longValue();
}
Run Code Online (Sandbox Code Playgroud)
由于Java不支持操作符重载,这是不可能的定义比较操作符的含义<和>任何类型的对象。换句话说:
Number a = new Long(1);
Number b = new Long(2);
if (a < b) // does NOT compile - objects cannot be compared using `<` or `>`!
Run Code Online (Sandbox Code Playgroud)
第二个示例进行编译的原因是自动装箱。该Long对象被自动转换为long你做这当然是相当的值。但是由于没有针对类型的对象的通用自动装箱Number,因此在第一种情况下不起作用。
那么我们如何检查溢出?我认为最简单的方法是先检查该double值:
private static long extractLong(Number value) {
double v = value.doubleValue();
if (v < Long.MIN_VALUE || v > Long.MAX_VALUE) {
throw new NumberFormatException(...);
}
return value.longValue();
}
Run Code Online (Sandbox Code Playgroud)
请注意,这并不涵盖其中value很大BigDecimal或BigInteger不能表示为double任一情况的情况。因此,您也需要进行instanceof检查。
警告:此测试使用的值大于或小于doubleValue()时不起作用。原因是由于浮点值的性质,从整数或十进制数到n的转换不准确。更具体地说,所有从到的值都将转换为一个相同的双值()。例:valueLong.MAX_VALUELong.MIN_VALUEdoubleLong.MAX_VALUE - 511Long.MAX_VALUE + 10259.223372036854776E18
double d1 = Long.MAX_VALUE - 511;
double d2 = Long.MAX_VALUE;
double d3 = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1025)).doubleValue();
// d1 == d2 == d3 due to lack of precision of double!
Run Code Online (Sandbox Code Playgroud)
但是,这意味着,上面的表达式v > Long.MAX_VALUE将是false对所有这些值虽然它们中的一些有效大于Long.MAX_VALUE:
long l = extractLong(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE));
// l is now -9223372036854775808 => overflow check failed!
Run Code Online (Sandbox Code Playgroud)
旁注:此处不必使用泛型!只需Number直接使用即可T,您可以传递各种数字。由于多态性,这从Java 1.0开始就可以使用...;)