我可以对Number基类进行算术运算吗?

时间:2010-10-06 13:56:40

标签: java

我正在尝试在Java中创建一个将对数字执行操作的泛型类。在以下示例中,添加如下:

public class Example <T extends Number> {

    public T add(T a, T b){
        return a + b;
    }

}

原谅我的天真,因为我对Java Generics相对较新。此代码无法使用错误编译:

  

对于参数类型T,T

,运算符+未定义

我认为通过添加“extends Number”,代码将被编译。是否可以执行此Java或我是否必须为每个Number类型创建重写方法?

7 个答案:

答案 0 :(得分:26)

Number没有与之关联的+运算符,也没有运算符重载。

但这会很好。

基本上,你要求java自动装载一个数字的目标,其中包括Integer,Float和Double,它们可以被自动装箱并且应用了一个加号运算符,但是,可能有任意数量的其他未知的数字后代无法自动装箱,直到运行时才能知道。 (该死的擦除)

答案 1 :(得分:20)

你的问题与泛型无关,而与运算符,基元与对象以及自动装箱有关。

想一想:

public static void main(String[] args) {
    Number a = new Integer(2);
    Number b = new Integer(3);
    Number c = a + b;
}

以上不编译

public static void main(String[] args) {
    Integer  a = new Integer(2);
    Integer b = new Integer(3);
    Number c = a + b;
}

上面的进行了编译,但仅仅是因为自动装箱 - 这是Java 5中引入的一种hacky语法粘合剂,并且仅在某些具体类型中有效(在编译时):int-Integer例如。

在幕后,Java编译器正在重写最后一个语句(“我必须取消装箱ab”才能将sum运算符应用于原始数据类型,并将结果装箱以将其分配给对象{ {1}}“)因此:

c

Java无法取消装箱 Number c = Integer.valueOf( a.intValue() + b.intValue() ); ,因为它在编译时不知道具体类型,因此无法猜测其原始对应物。

答案 2 :(得分:5)

你可以做这样的事情

    class Example <T extends Number> {
        public Number add(T a, T b){
            return new Double(a.doubleValue() + b.doubleValue());
        }
    }

答案 3 :(得分:2)

是的,内森是对的。如果你想要这样的东西,你必须自己写一下

public class Example <T extends Number> {
    private final Calculator<T> calc;
    public Example(Calculator<T> calc) {
       this.calc = calc;
    } 

    public T add(T a, T b){
        return calc.add(a,b);
    }
}

public interface Calculator<T extends Number> {
    public T add(T a, T b);
}

public class IntCalc implements Calculator<Integer> {
    public final static IntCalc INSTANCE = new IntCalc();
    private IntCalc(){}
    public Integer add(Integer a, Integer b) { return a + b; }
}

...

Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE);
System.out.println(ex.add(12,13));

太糟糕的Java没有类型类(Haskell)或隐式对象(Scala),这个任务将是一个完美的用例......

答案 4 :(得分:1)

这个问题也有类似的问题,答案是你不能那样做。

您可以检查a和b是否为Long / Double / Integer / etc的实例。并将add方法委托给:

public Integer add(Integer a, Integer b) {
    return a+b; // this actually uses auto boxing and unboxing to int
}

并且您需要为扩展Number的每种类型创建一个,因此这不可行。换句话说,不要将泛型用于数值运算。作为超类的数量非常有限。

答案 5 :(得分:0)

考虑Example<Number>+将如何处理? add甚至Number之内都没有Integer或类似内容。

更糟糕的是考虑final class FunkyNumber extends Number { ... weird stuff, no add op ... }

答案 6 :(得分:0)

即使是java运行时库也存在这个问题,处理基元的大多数方法都必须复制相同的功能。

最快的选择是为一种类型编写代码,然后复制它并替换类型以生成其他类型的方法。一个简短的脚本应该足以做到这一点。