[英]Java Generics won't compile
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 get: 错误获得:
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
Can't understand what i'm doing wrong? 无法理解我在做什么错? If i change SZX with Integer - all works fine but why with generics code won't compile?
如果我使用Integer更改SZX-一切正常,但为什么不能使用泛型代码编译?
Refactored code to: 重构代码为:
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
So, S supposed to be an Integer or any subclass of Integer class, in any way it definitely should be possible to + their values. 因此,S应该是Integer或Integer类的任何子类,以任何方式肯定都可以+其值。 What's wrong with this version?
这个版本有什么问题?
S extends Integer
but int cannot be converted to S
, how it could be? S extends Integer
但int cannot be converted to S
,怎么可能呢? Why there is no autoboxing? 为什么没有自动装箱?
The problem you're experiencing is because there is no +
operator defined for Number
, only specific subclasses of Number
. 您遇到的问题是,因为没有
+
的定义运营商Number
,只对特定的子类Number
。 For example, +
is defined for Integer
, Double
etc, but not BigInteger
, BigDecimal
or any other non-standard implementation of Number
. 例如,
+
是为Integer
, Double
等定义的,但不是BigInteger
, BigDecimal
或Number
任何其他非标准实现的。
There is no good way to do generic addition. 没有通用的加法的好方法。 You end up having to provide a
BinaryOperator<S>
, so your code looks like: 您最终不得不提供
BinaryOperator<S>
,因此您的代码如下所示:
sum(1, 2, Integer::sum);
sum(1.0, 2.0, Double::sum);
which is more verbose than just: 这不仅仅是冗长的:
1 + 2
1.0 + 2.0
The compiler requires +
to be defined for the compile-time types of v1
and v2
. 编译器需要为
v1
和v2
的编译时类型定义+
。 It doesn't matter if they are Integer
(or whatever) at runtime: the decision as to whether to allow the +
is made by the compiler, because it has to be able to guarantee that the method is type-safe for any arguments. 它们在运行时是否为
Integer
(或其他任何值)无关紧要:是否允许+
由编译器决定,因为它必须能够保证该方法对于任何参数都是类型安全的。
The method above is compiled to this: 上面的方法编译为此:
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;
}
This is called type erasure . 这称为类型擦除 。
If +
isn't defined for a Number
, this code isn't allowed. 如果未为
Number
定义+
,则不允许使用此代码。
As a general solution for all inbuilt Number
extensions: 对于所有内置的通用解决方案
Number
扩展:
public static Number sum(final Number a, final Number b) {
return new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
}
(Note: there's no guarantee that toString()
will give a String
which is parseable by BigDecimal
but it does for all the inbuilt JDK Number
extensions to the best of my knowledge.) (注意:不能保证
toString()
会给出一个可由BigDecimal
解析的String
,但据我所知,它对所有内置的JDK Number
扩展都是如此。)
If you wanted to do something more clever, you could do some checks with instanceof
to find the types of the inputs and work from there, but I tried that once for implementing Comparable
between all Number
s and the performance wasn't any better than casting to BigDecimal
. 如果您想做一些更聪明的事情,可以对
instanceof
进行一些检查,以找到输入的类型并从那里开始工作,但是我尝试过一次,以便在所有Number
之间实现Comparable
,而性能也没有比强制转换更好到BigDecimal
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.