为什么在同一个类中有以下两个方法是不合法的?
class Test{
void add(Set<Integer> ii){}
void add(Set<String> ss){}
}
我得到编译错误
方法add(Set)与类型Test中的另一个方法具有相同的擦除添加(Set)。
虽然我可以绕过它,但我想知道为什么javac不喜欢这样。
我可以看到,在许多情况下,这两个方法的逻辑非常相似,可以用一个方法来代替
public void add(Set<?> set){}
方法,但情况并非总是如此。
如果你想有两个接受这些参数的构造函数,这是非常烦人的,因为你不能只改变其中一个构造函数的名字。
该规则旨在避免在仍然使用原始类型的遗留代码中发生冲突。
下面是一个来自JLS的说明,说明了为什么不允许这样做。假设,在Java引入泛型之前,我写了一些这样的代码:
class CollectionConverter {
List toList(Collection c) {...}
}
你扩展我的类,像这样:
class Overrider extends CollectionConverter{
List toList(Collection c) {...}
}
在引入泛型之后,我决定更新我的库。
class CollectionConverter {
<T> List<T> toList(Collection<T> c) {...}
}
你还没有准备好做任何更新,所以你离开你的Overrider类。为了正确地重写toList()方法,语言设计者决定原始类型与任何泛化类型“重写等效”。这意味着,尽管您的方法签名不再正式等于我的超类的签名,但您的方法仍然被重写。
现在,时间流逝,您决定准备更新类。但你搞砸了一点,而不是编辑现有的原始toList()方法,你添加了一个新方法,像这样:
class Overrider extends CollectionConverter {
@Override
List toList(Collection c) {...}
@Override
<T> List<T> toList(Collection<T> c) {...}
}
由于原始类型的重写等价性,这两个方法都具有重写toList(Collection<T>)方法的有效形式。当然,编译器需要解析单个方法。为了消除这种模糊性,类不允许有多个重写等效的方法——即在擦除后具有相同参数类型的多个方法。
关键在于,这是一种语言规则,旨在保持与使用原始类型的旧代码的兼容性。它不是删除类型参数所需要的限制;因为方法解析发生在编译时,向方法标识符添加泛型类型就足够了。