public class GenMethodDemo{
public GenMethodDemo(){
Sum.<Integer,Integer,Integer>sum(1,2);
}
public static void main(String args[]){
new GenMethodDemo();
}
}
class Sum{
public static final <S extends Number,Z extends S,X extends S> S sum(Z v1,X v2){
System.out.printf("v1=%1$s,v2=%2$s%n",v1.getClass(),v2.getClass());
return v1+v2;
}
错误获取:
error: bad operand types for binary operator '+'
return v1+v2;
first type: Z
second type: X
where Z,S,X are type-variables:
Z extends S declared in method <S,Z,X>sum(Z,X)
S extends Number declared in method <S,Z,X>sum(Z,X)
X extends S declared in method <S,Z,X>sum(Z,X)
1 error
不明白我在做什么错?如果我使用Integer更改S.Z.X-一切正常,但为什么使用泛型代码无法编译?
将代码重构为:
public class GenMethodDemo2{
public GenMethodDemo2(){
Sum.<Integer>sum(1,2);
}
public static void main(String args[]){
new GenMethodDemo2();
}
}
class Sum{
public static final <S extends Integer> S sum(S v1,S v2){
System.out.printf("v1=%1$s, v2=%2$s%n",v1.getClass(),v2.getClass());
return v1+v2;
}
}
error: incompatible types: int cannot be converted to S
return v1+v2;
where S is a type-variable:
S extends Integer declared in method <S>sum(S,S)
1 error
因此,S应该是Integer或Integer类的任何子类,以任何方式肯定都可以+其值。这个版本怎么了?
S extends Integer
,但int cannot be converted to S
可能如何?为什么没有自动装箱?
答案 0 :(得分:10)
您遇到的问题是因为没有为+
定义Number
运算符,只有Number
的特定子类。例如,为+
,Integer
等定义了Double
,但没有为BigInteger
的{{1}},BigDecimal
或任何其他非标准实现定义
没有通用的加法方法。您最终不得不提供一个Number
,因此您的代码如下所示:
BinaryOperator<S>
这不仅冗长:
sum(1, 2, Integer::sum);
sum(1.0, 2.0, Double::sum);
编译器要求为1 + 2
1.0 + 2.0
和+
的编译时间类型定义v1
。它们在运行时是否为v2
(或其他任何值)都没有关系:是否允许Integer
的决定由编译器做出,因为它必须能够保证该方法对于任何参数都是类型安全的。
上面的方法编译为此:
+
这称为type erasure。
如果未为 public static final Number sum(Number v1, Number v2){
System.out.printf("v1=%1$s,v2=%2$s%n",v1.getClass(),v2.getClass());
return v1+v2;
}
定义+
,则不允许使用此代码。
答案 1 :(得分:-1)
作为所有内置Number
扩展名的通用解决方案:
public static Number sum(final Number a, final Number b) {
return new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
}
(注意:不能保证toString()
会给出String
可以解析的BigDecimal
,但是对于所有内置的JDK Number
扩展都做到了最好我的知识。)
如果您想做一些更聪明的事情,可以对instanceof
进行一些检查,以找到输入的类型并从那里开始工作,但是我尝试过一次在所有{之间实现Comparable
{1}} s,其性能丝毫不逊色于Number
。