方法与类型中的另一个方法具有相同的擦除

为什么在同一个类中使用以下两种方法是不合法的

类测试{
void add(Set<Integer>ii){}
void add(Set<String>ss){}
}

我得到编译错误

方法add(Set)与型式试验中的另一种方法具有相同的擦除add(Set)

虽然我可以解决这个问题,但我想知道为什么javac不喜欢这个

我可以看到,在许多情况下,这两种方法的逻辑非常相似,可以用一个单一的方法代替

public void add(Set<?>Set){

方法,但情况并非总是如此

如果您想让两个构造函数接受这些参数,这就特别烦人了,因为这样您就不能只更改其中一个构造函数的名称

此规则旨在避免仍然使用原始类型的遗留代码中的冲突

下面是一个说明为什么不允许这样做的例子,取自JLS。假设在泛型引入Java之前,我编写了如下代码:

类集合转换器{
列表列表(集合c){…}
}

你扩展了我的课堂,就像这样:

类重写器扩展了CollectionConverter{
列表列表(集合c){…}
}

在引入泛型之后,我决定更新我的库

类集合转换器{
<T>列表<T>列表(集合<T>c){…}
}

您还没有准备好进行任何更新,因此您将重写器类留在一旁。为了正确重写toList()方法,语言设计者决定原始类型“重写等价于”任何泛型类型。这意味着,尽管您的方法签名在形式上不再等于我的超类签名,但您的方法仍然重写

现在,随着时间的推移,您决定准备好更新您的类。但是你把事情搞砸了,你没有编辑现有的原始toList()方法,而是添加了一个新方法,如下所示:

类重写器扩展了CollectionConverter{
@凌驾
列表列表(集合c){…}
@凌驾
<T>列表<T>列表(集合<T>c){…}
}

由于原始类型的重写等价性,这两种方法都以有效的形式重写toList(Collection<T>)方法。但当然,编译器需要解析单个方法。为了消除这种歧义,类不允许有多个重写等效的方法—即,擦除后具有相同参数类型的多个方法

关键在于,这是一种语言规则,旨在维护与使用原始类型的旧代码的兼容性。它不是类型参数擦除所需的限制;因为方法解析发生在编译时,所以向方法标识符添加泛型类型就足够了

发表评论