Java中的类型擦除和重载:为什么这样做?

我有以下代码:

public class Pair { public T first; public U second; } public class Test { public int method( Pair pair ) { return 0; } public double method( Pair pair ) { return 1.0; } } 

这实际上编译和工作就像人们期望的那样。 但是如果返回类型相同,则不会编译,预期的“名称冲突:方法(对)和方法(对)具有相同的擦除”

鉴于返回类型不是方法签名的一部分,这种重载怎么可能?

考虑以下4种方法

  Java code bytecode m1: Byte f(List list) f List -> Byte m2: Long f(List list) f List -> Long m3: Byte f(List list) f List -> Byte m4: Long f(List list) f List -> Long 

根据当前的Java语言规范,

  • m1和m2不能共存,m3和m4也不能共存。 因为它们具有相同的参数类型。

  • m1和m3可以共存,m1和m4也可以共存。 因为它们有不同的参数类型。

但是javac 6只允许m1 + m4,而不是m1 + m3。 这与方法的字节码表示有关,包括返回类型。 因此,m1 + m4可以,但不是m1 + m3。

这是一个棘手的问题,Java和JVM规范并不是一致的。 javac没有“正确”的方式。

虽然很糟糕,但好消息是,重载是一种虚荣,而不是必需品。 我们总是可以为这些方法使用不同的,更具描述性和不同的名称。

重载在编译时完成。

尽管通用参数在运行时被擦除,但编译器仍可使用它们来解决重载问题。

Java方法签名实际上包括返回类型; 如果你曾经和JNI合作过,你会看到像(LPair;)D(LPair;)我这样的类型描述符。 最后一个字符表示两种方法的返回类型。 虽然Java语言规则是两个重载方法的参数必须不同,但类文件格式实际上可以仅基于它们的返回类型来区分方法。 当存在generics类型信息以允许编译器根据其参数解析重载时,只要返回类型不同,擦除将具有不同的签名,并且一切正常。 但是,如果返回类型相同,则在擦除后方法具有相同的签名,类文件无法区分,并且您遇到了问题。

我相信你实际上是在打字错误。 通过说第一种方法采用Pair,你给它一个非常具体的类型。 这就像说方法(String,String)。 Pair的第二种方法就像说方法(Person,Person)。 这在打字级别上也非常具体。 如果你将你的方法改为方法(Pair ,Pair )并且有两次,你就会打破编译。

如此简短的回答:因为你强烈地输入了对来意味着两个不同的东西,generics不是在起作用,只是输入规则。