Search code examples
javagenericsinterfaceextendssubtyping

How do I correctly restrict a generic interface to extend Number class in Java and be able to run it in another class?


Am trying to understand how to extend an interface and use it in another class but each time the compiler throws a casting error. I have tried using wildcard in the method printResult but it does not work. What could be the issue here? It only works with Integer.

public interface Computable <T extends Number>
{
    public T compute(T x, T y);    
}

------------------------------------------------------------

public class TestComputable
{
    public static void main(String[] args)
    {
        Computable<Float> comp;
        comp = (x, y) -> x + y;
        printResult(comp);
    }
}

public static void printResult(Computable compIn)
{
    System.out.println("The result is: " + compIn.compute(10, 5));
}

Solution

  • Your code will only work for Integer because you're passing in Integer arguments to the Computable.

    If you want to pass in e.g. "the Float equivalent of the Integer", you need to pass in a Function to convert the Integer to a Float; more generally, if you want to pass in "the T equivalent of the Integer", you need to pass in a Function to convert the Integer to a T:

    public static <T extends Number> void printResult(Computable<T> compIn, Function<? super Integer, ? extends T> fn)
    {
        System.out.println("The result is: " + compIn.compute(fn.apply(10), fn.apply(5)));
    }
    

    and invoke like:

    printResult(comp, Integer::floatValue);
    

    Alternatively, you can pass in the correctly-typed arguments explicitly:

    public static <T extends Number> void printResult(Computable<T> compIn, T a, T b) {
        // ... Something with compln.compute(a, b)
    }
    

    and invoke like:

    printResult(comp, 10.f, 5.f);
    

    The only way you can make this work without passing in additional parameters is to only accept a Computable that can accept any Number, or at least that can accept arguments of the type you are passing in:

    public static void printResult(Computable<Number> compIn) { ... }
    public static void printResult(Computable<Integer> compIn) { ... }
    public static void printResult(Computable<? super Integer> compIn) { ... }