Java泛型无法编译

时间:2019-06-02 23:23:35

标签: java generics

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可能如何?为什么没有自动装箱?

2 个答案:

答案 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