简体   繁体   中英

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

This is where the compiler actually tried to help you by emitting a warning about using a raw type: if you change the printResult method to use the proper type argument as follows:

public static void printResult(Computable<Float> compIn) { // instead of Computable compIn

then the compiler would have shown an error at compile time:

// Now the compiler throws error:
// the method compute(Float, Float) is not applicable for the arguments (int, int)
System.out.println("The result is: " + compIn.compute(10, 5));

This is why you should always avoid using raw types, the compiler can infer the proper binding of types.

Now that we have the compilation error message, we know what the problem is: the arguments 10 and 5 are int values, while the interface Computable expects Float values, so you can fix them to be treated as float values:

System.out.println("The result is: " + compIn.compute(10f, 5f));

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

If you want to pass in eg "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) { ... }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM