views:

144

answers:

7

I am trying to create a generic class in Java that will perform operations on numbers. In the following example, addition, as follows:

public class Example <T extends Number> {

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

}

Forgive my naivety as I am relatively new to Java Generics. This code fails to compile with the error:

The operator + is undefined for the argument type(s) T, T

I thought that with the addition of "extends Number" the code would compile. Is it possible to do this Java or will I have to create overridden methods for each Number type?

+12  A: 

Number does not have a + operator associated with it, nor can it since there is no operator overloading.

It would be nice though.

Basically, you are asking java to autobox a descedant of Number which happens to include Integer, Float and Double, that could be autoboxed and have a plus operator applied, however, there could be any number of other unknown descendants of Number that cannot be autoboxed, and this cannot be known until runtime. (Damn erasure)

Nathan Feger
"there could be any number of other unknown descendants of Number that cannot be autoboxed," such as `BigInteger` and `BigDecimal`, which both extend `Number`.
R. Bemrose
A: 

Consider Example<Number>, how would + work on that? There is no add or similar in Number or even the likes of Integer.

Worse consider final class FunkyNumber extends Number { ... weird stuff, no add op ... }.

Tom Hawtin - tackline
A: 

There are similar questions to this one, and the answer is you can't do it like that.

You could check if a and b are an instance of Long/Double/Integer/etc. and delegate the add to methods like:

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

And you would need to create one for every type that extends Number, so that's not really feasible. In other words, don't use generics for numeric operations. Number as a superclass is pretty limited.

Andrei Fierbinteanu
+3  A: 

Your problem is not really related to generics, rather to operators, primitives vs objects, and autoboxing.

Think about this:

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

The above does not compile

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

The above does compile, but only because of autoboxing - which is kind of a hacky syntax glue introduced in Java 5, and only works (in compile time) with some concrete types : int-Integer for example.

Behind the scenes, the Java compiler is rewriting the above as

    Number c = Integer.valueOf(a.intValue() + b.intValue());

Java can't do autoboxing on a Number because it does not know at compile time the concrete type and hence its primitive counterpart.

leonbloy
+1  A: 

Yes, Nathan is correct. If you want something like this, you have to write it yourself

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));

Too bad Java has no type classes (Haskell) or implicit objects (Scala), this task would be a perfect use case...

Landei
A: 

You can do something like this

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

Even the java runtime library has this problem, most of the methods dealing with primitives have to duplicate the same functionality.

The fastest option would be to write your code for one type and then copy it and replace the type to generate the methods for the other types. A short script should be enough to do this.

josefx