问题
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:
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. 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