Generic type extending Number, calculations

2019-01-12 12:19发布

问题:

I've made an interface of math operation with one method, calculate, taking various number of arguments

public interface MathOperation {
    public <T extends Number> T calculate(T... args);
}

There's also simple implementation of this class, which does not work:

private class Sum implements MathOperation {
    @Override
    public <T extends Number> T calculate(T... args) {
        return args[0] + args[1];
    }
}

The problem is:

bad operand types for binary operator '+'
  first type:  T
  second type: T
  where T is a type-variable:
    T extends Number declared in method <T>calculate(T...)

What I'm trying to achieve is a simple class, taking for example two Doubles and returning Double as well.

Is there possibility to achieve this?

回答1:

+ cannot be applied to types that extend Number. new Integer(5) + new Integer(5) works because of autoboxing. You will have to look at the runtime type of args and do the operation accordingly.

Something on the lines of:

private class Sum implements MathOperation {
    @Override
    public <T extends Number> T calculate(Class<T> clazz, T... args) {
         if (clazz.equals(Integer.class))
         {
             return Integer.class.cast(args[0]) + Integer.class.cast(args[1]);
         } else (....) 
    }
}


回答2:

You can test the runtime type as shown in the other answers. Or you can try a different design: Create an abstract class that works as a factory:

interface MathContext<T extends Number> {

    ...

    T valueOf(double d);
    T valueOf(int i);
    T add (T... args);
}

And concrete classes for the types that you want to use:

DoubleContext implements MathContext<Double> {

    ...

    Double valueOf(int i) {
        return i;
    }

    Double valueOf(double d) {
        return d;
    }

    Double add(Double... args) {
        Double res = 0;
        for (Double arg: args)  {
            res += arg;
        }
        return res;
    }

}

Now you could implement your MathOperation using that class. However, it's not really needed any more.