为什么不编译? 我想知道根本原因。
如果
List<String>
与
的类型不同 List<Integer>
为什么
public String convert(List<String> strings) { return null; }
和
public String convert(List<Integer> strings) { return null; }
发表含糊不清的声明?
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;
}
}
答案 0 :(得分:7)
泛型只是一种编译工具,可以使代码更强类型化
编译后,泛型确实被删除了。它被称为类型擦除
因此,List<Integer>
和List<String>
在Java字节码中只变为List
并且您不能拥有多个具有相同签名的方法
而编译错误。
来自documentation:
泛型被引入Java语言以提供更紧密的类型 在编译时检查并支持通用编程。至 实现泛型,Java编译器将类型擦除应用于
将泛型类型中的所有类型参数替换为其边界或 对象,如果类型参数是无界的。生成的字节码, 因此,只包含普通的类,接口和方法。
如有必要,插入类型转换以保护类型安全。
生成桥接方法以保留扩展泛型中的多态性 类型。
答案 1 :(得分:4)
不幸的是两个都是列表。 JDK / JVM不查看泛型类型,但它们看到采用相同对象类型(列表接口)的相同方法。
如果您看看@duffymo发布的link(在评论中) - 它解释了类型擦除的概念。引用:
类型删除
泛型被引入到Java语言中,以便在编译时提供更严格的类型检查并支持泛型编程。至 实现泛型,Java编译器将类型擦除应用于:
将泛型类型中的所有类型参数替换为其边界或 对象,如果类型参数是无界的。生成的字节码, 因此,只包含普通的类,接口和方法。
如有必要,插入类型转换以保持类型安全。
- 生成桥接方法以保留扩展泛型类型中的多态性。 类型擦除确保不为参数化创建新类 类型;因此,泛型不会产生运行时开销。
醇>
答案 2 :(得分:1)
当Java在JDK 5.0中引入泛型时,生成的字节码没有改变(对于泛型)。较旧版本的Java没有泛型,因此列表之类的类没有元素类型信息。
基本上只有Java编译器会看到泛型,它会对编译时间进行额外的检查,并添加额外的代码来进行类型转换,而不必再进行类转换。
在生成的图像中,此信息将被删除,因此Java运行时不再可见。在运行时映像中,两者都只是List
个实例,因此无法区分。
由于Java运行时的动态行为,代码不直接链接到方法(就像在非虚拟C ++方法中那样),而是描述要调用的方法签名和名称。由于类型擦除,签名将变得相同,因此Java运行时无法决定调用哪个方法。
答案 3 :(得分:0)
如果你这样做:
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;
}
}
用户泛型查找方法convert1
和convert2
:
Method[] methods = Converter.class.getMethods();
您会发现方法convert1
和convert2
具有相同的声明参数java.util.List
。因此,一旦编译,您将发现参数消失。