Java 8 generic functions should be ambiguous but fail at run time

I'm trying to migrate Java 7 code to Java 8, so my code is similar to:

package tests;

import java.util.Arrays;
import java.util.Map;

public class Tests {
    private static interface ComparableMap<K,V> extends Map<K,V>,Comparable {}

    public static void main(String[] args) {
        func(getString());
    }

    private static void func(Comparable...input){
        System.out.println(Arrays.toString(input));
    }

    private static void func(ComparableMap <?,?> m){
        System.out.println(m);
    }

    private static <T extends Comparable> T getString(){
        return (T) "aaa";
    }
}

In Java 7, it works normally. In Java 8, I get:

If I change a function definition to:

private static <T> T getString(){
        return (T) "aaa";
    }

Compilation will fail: error:

Why didn't the Java 8 compiler fail in the first case? (it seems wrong to me) can you change the second overloaded function to call the first function with the varargs parameter without changing the call itself?

Solution

Compilation error

In the first case, the method getString is required to return a comparable instance The compiler looks for the overload of func method. It only finds a method that can accept comparable: func (comparable... Input) Map does not implement this interface, so the second overload is not applicable There is no ambiguity

In the second case, getString can return anything Both overloads are valid and therefore ambiguous However, please note that in both cases, the cast to t is unsafe / wrong

Usafe actors

The generic method you write basically tells the compiler that "I can return instances of any class you want to implement comparable" But you can't actually keep that promise

It can be said that I have the following code:

String str = getString();
Integer num = getString();

This code will be compiled. Both string and integer implement the comparable interface The second line fails at run time: the code attempts to convert string to integer

Your second case is also wrong for the same reason as I explained above It promises that it can return any type you want It seems that it can't keep this promise (runnable here is a random example, it can be anything):

Runnable run = getString()

Your updated code

The compiler sees two possible overloads, func (comparable... Input) and func (comparable map m) It prefers the second because the varargs method is always the last choice (for compatibility reasons) All these are core behaviors

Then the code throws ClassCastException because your getString method does not guarantee its promise (let the caller decide what type of comparable to return)

How?

The fundamental problem is that your getString method makes a false promise So I really don't know what the code is trying to accomplish If you can elaborate, we can help you develop further

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>