32

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?

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
Tom Smith
  • 321
  • 1
  • 3
  • 4
  • 1
    Might want to check out Scala or Groovy if you want to do this kind of thing. They have operator overloading, and domain specific language functionality :) – Chris Dennett Oct 09 '10 at 18:54

7 Answers7

27

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
  • 19,122
  • 11
  • 62
  • 71
  • 3
    "there could be any number of other unknown descendants of Number that cannot be autoboxed," such as `BigInteger` and `BigDecimal`, which both extend `Number`. – Powerlord Oct 06 '10 at 14:53
  • I think, if Number had .add(a,b) .sub(a,b) .mult(a,b) ... we could simply use these instead and so use generics, may be an interface NumberHero being implemented by IntegerHero that could extend a class similar to Integer (as we cannot extend final classes), could do the trick? – Aquarius Power Dec 22 '15 at 19:05
21

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.

leonbloy
  • 73,180
  • 20
  • 142
  • 190
7

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());
        }
    }
Stan Kurilin
  • 15,614
  • 21
  • 81
  • 132
  • I can't believe even in 2020 Java doesn't provide a superclass that contains operations like add/subtract/multiply/division built in. I'd love to be able to extend from a class and have T be an Integer, Double etc and the number operations work out of the box! – Shane Sepac Aug 08 '20 at 18:41
2

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
  • 54,104
  • 13
  • 100
  • 195
1

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
  • 7,656
  • 3
  • 31
  • 45
0

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
  • 145,806
  • 30
  • 211
  • 305
0

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
  • 15,506
  • 6
  • 38
  • 63