可能重复:
方法与类型中的另一种方法具有相同的擦除

在我的一个课程中,我想定义这两个方法:

private void add(List<ChangeSet> changeSetList) {
    for (ChangeSet changeSet : changeSetList) {
        add(changeSet);
    }
}

private void add(List<Change> changeList) {
    for (Change change : changeList) {
        add(change);
    }
}

然后我收到以下错误:

Method add(List<Change>) has the same erasure add(List<E>) as another method in type DataRetriever

为什么不允许这样做? 这样的方法定义有什么问题? 我应该怎么做才能避免它呢? 我不想重命名其中一种方法。

===============>>#1 票数:11 已采纳

这就是Java的类型系统如何“工作”。 泛型List<Change>List<ChangeSet>实际上不是不同的类型。 泛型参数只是编译器执行某些检查和某些强制转换的提示。 然而,就JVM和类型系统而言,这两种类型实际上都被“擦除”到List<Object> (或者只是List如果你愿意的话),这两种类型实际上是相同的,没有内部差异。 因此,您实际上不能对不同的泛型参数进行重载 ,因为就重载决策而言,这两种类型是相同的。

===============>>#2 票数:7

此限制是语言语法的一部分,而不是Java运行时本身。 本质上,此规则旨在避免仍使用原始类型的遗留代码中的冲突。

javac这样的编译器会拒绝这种类型的重载,但是如果你通过其他方式创建一个类(编写自己的编译器,或使用像ASM这样的字节码工程库),签名只有类型参数不同,那么javac编译器将会解决方法在您的类中调用正确的方法。

以下是从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>)方法。 但是,当然,编译器需要解决单个方法。 为了消除这种歧义,不允许类具有多个覆盖等效的方法 - 即擦除后具有相同参数类型的多个方法。

关键是这是一种语言规则,旨在允许继续使用原始类型,而不是因类型参数的擦除而产生的限制。

如果您消除遗留代码(例如,使用您自己的,非严格的Java语言),这种类型的重载功能就完美无缺。 由于方法解析在编译时发生,因此在擦除之前,不需要输入类型来实现此功能。

===============>>#3 票数:2

除了adarshr和Kerrek的答案之外,为什么不把它变成通用的,如下所示:

private <T> void add(List<T> changeList) {
    for (T change : changeList) {
        add(change);
    }
}

这应该适用于两种情况......

===============>>#4 票数:1

因为泛型只是编译时帮助你。 编译后,字节码中不会存储与泛型有关的信息。

看看这个:

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

===============>>#5 票数:0

在类型擦除之后,两个方法都将具有private void add(List)的签名,这是不允许的。

您需要重命名方法或传递另一个参数,如列表值的类。

  ask by translate from so

未解决问题?本站智能推荐: