Overload: why List<String> and List<Integer> make ambiguous declaration? [duplicate]

点点圈 提交于 2021-01-28 05:06:56

问题


Why doesn't this compile? I want to know the underlying reason.

If

 List<String> 

is not the same type as

 List<Integer> 

why

public String convert(List<String> strings) { return null; }

and

public String convert(List<Integer> strings) { return null; }

make an ambiguous declaration?

public class Converter {

    public void why() {
        List<String> strings = null;
        List<Integer> integers = null;

        strings = integers; // type mismatch
    }

    public String convert(List<String> strings) {
        // error: why is this ambiguous ?
        return null;
    }

    public String convert(List<Integer> strings) {
        // error: why is this ambiguous ?
        return null;
    }

}

回答1:


Generics are just a compilation artefact to make the code more strongly typed.
After compilation, generics are indeed erased. It is called type erasure .
So List<Integer> and List<String> become just List in the Java bytecode.
And you cannot have more than one method with the same signature.
Whereas the compilation error.
From the documentation :

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.

  • Insert type casts if necessary to preserve type safety.

  • Generate bridge methods to preserve polymorphism in extended generic types.




回答2:


Explanation

Unfortunately both are Lists. The JDK/JVM do not look at the generic type, but they see the same method taking the same object type (a list interface).

If you have a look @ the link posted by @duffymo (in the comments) - it explains the concept of Type Erasure. Quoting:

Type Erasure

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

  1. Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.

  2. Insert type casts if necessary to preserve type safety.

  3. Generate bridge methods to preserve polymorphism in extended generic types. Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.



回答3:


When Java introduced generics in JDK 5.0 the generated bytecode did not change (for generics). Older versions of Java didn't have generics, so classes like lists didn't have element type information.

Basically generics are only seen by the Java compiler which does extra checks on compile time and adds extra code to do class casts that you do not have to do anymore.

In the resulting image this information is erased, and thus not visible to the Java runtime anymore. In the runtime image both are just List instances, and thus indistinguishable from each other.

Because of the dynamic behaviour of the Java runtime the code does not link directly to a method (as it would do in a non-virtual C++ method) but describes the method signature and name to be called. Because of type erasure the signature would become the same and thus the Java runtime can't decide which of the methods to call.




回答4:


If you were to do:

public class Converter {

public void why() {
    List<String> strings = null;
    List<Integer> integers = null;

    strings = integers; // type mismatch
}

public String convert1(List<String> strings) {
    // error: why is this ambiguous ?
    return null;
}

public String convert2(List<Integer> strings) {
    // error: why is this ambiguous ?
    return null;
}

}

And user generics to find the methods convert1 and convert2:

Method[] methods = Converter.class.getMethods();

You will find that methods convert1 and convert2 have the same declared parameters java.util.List. So once compiled you will find that the parameters disappear.



来源:https://stackoverflow.com/questions/46527036/overload-why-liststring-and-listinteger-make-ambiguous-declaration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!