Tom Smith
Tom Smith

Reputation: 321

Can I do arithmetic operations on the Number baseclass?

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?

Upvotes: 32

Views: 22946

Answers (7)

leonbloy
leonbloy

Reputation: 75906

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 last statement ("I must unbox a and b to apply the sum operator with primitive datatypes, and box the result to assign it to object c") thus:

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

Java can't unbox a Number because it does not know at compile time the concrete type and hence it cannot guess its primitive counterpart.

Upvotes: 21

josefx
josefx

Reputation: 15656

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.

Upvotes: 0

Landei
Landei

Reputation: 54574

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...

Upvotes: 2

Stan Kurilin
Stan Kurilin

Reputation: 15792

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

Upvotes: 7

Andrei Fierbinteanu
Andrei Fierbinteanu

Reputation: 7826

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.

Upvotes: 1

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

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 ... }.

Upvotes: 0

Nathan Feger
Nathan Feger

Reputation: 19496

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)

Upvotes: 27

Related Questions