Java 8 type inference causes generic types to be omitted at call time

After upgrading to Java 1.8, I encountered a problem with generic methods, which is good for Java 1.6 and 1.7

public class ExtraSortList<E> extends ArrayList<E> {
    ExtraSortList(E... elements) {
        super(Arrays.asList(elements));
    }

    public List<E> sortedCopy(Comparator<? super E> c) {
        List<E> sorted = new ArrayList<E>(this);
        Collections.sort(sorted,c);
        return sorted;
    }

    public static void main(String[] args) {
        ExtraSortList<String> stringList = new ExtraSortList<>("foo","bar");

        Comparator<? super String> compGen = null;
        String firstGen = stringList.sortedCopy(compGen).get(0); // works fine

        Comparator compRaw = null;
        String firstRaw = stringList.sortedCopy(compRaw).get(0); // compiler ERROR: Type mismatch: cannot convert from Object to String
    }
}

I tried Oracle javac (1.8.0_92) and eclipse JDT (4.6.1) compilers Both are the same result (the error message is a little different, but basically the same)

In addition to the fact that errors can be prevented by avoiding primitive types, it puzzles me because I don't understand the reason

Why does the raw method parameter of sortedcopy method have any effect on the generic type of the return value? Generic types are already defined at the class level The method does not define a separate generic type The type of the reference list is < string >, and so should the returned list

Why does Java 8 discard generic types in classes on return values?

Edit: if the method signature of sortedcopy is changed (indicated by biziclop)

public List<E> sortedCopy(Comparator c) {

Then the compiler does consider the generic type E from the type extrasortlist < E > and will not make an error But now the parameter C is the original type, so the compiler cannot verify the generic type of the provided comparator

Editor: I've made some comments on the Java language specification. Now I think about whether I lack understanding or whether this is a defect of the compiler Because:

>The generic type E of scope of a declaration is the extrasortlist class, which includes the method sortedcopy. > The method sortedcopy itself does not declare generic type variables, but only references type variables from the class scope. See generic methods > JLS in JLS, which is also described in the same part

>The reference stringlist is defined using string, so the compiler does not need to infer the type fore in the call of sortedcopy because it has been defined. > Because stringlist already has the specific type of E, the parameter C should be comparator for a given call. > The return type should also use the materialized type E, so it should be list < string >

This is my current understanding of how I think the java compiler should evaluate calls If I am wrong, it would be good to explain why my hypothesis is wrong

Solution

The final answer to this question:

As @ Jesper has already mentioned, you should not use primitive types (especially generic in many cases) Because you passed a comparator without a generic type, it actually didn't You can treat e - Generic as null to make it easier So your code becomes:

public List sortedCopy(Comparator c) {
    List sorted = new ArrayList(this);
    Collections.sort(sorted,c);
    return sorted;
}

Now you're trying / assuming that you get a string from a list without generics, so you get an object (so it's a superclass of everything)

About why the raw type parameter has no effect on the return type, because you do not specify a certain abstraction level For example, you must define the type that generic must extend / implement to achieve at least this (compilation error)

public class ExtraSortList<E extends String> extends ArrayList<E> {

At present, only its string or class is allowed to be extended (this is impossible because the string is final) With it, your backup type will be string

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
分享
二维码
< <上一篇
下一篇>>