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

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

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

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

4回复

java是否应该允许类名定义与泛型类型参数相同?

我在同一个包test创建了类似下面的类。 它只是为了测试java是否真的允许它。 确实如此,但问题就出现了。 上面的代码给出了多个编译问题 它清楚地表明编译器在E和E类之间混淆了相同的T. 因此,解决方法是使用包定义它的真实类型。 现在,如果所有这些类都在def
3回复

Java泛型类型参数[重复]

这个问题在这里已有答案: 获取java.util.List的通用类型 14个答案 我有一个方法,它以List<?>作为参数。 在method ,我怎么知道,如果arg是一个List的ClassA或List的ClassB ?
1回复

Java泛型中的泛型类型参数

有没有一种方法可以将通用类型传递给像 在这里, Result将Wrapper类型参数T and R的类型之一。 Result接口中的getResult方法返回R 我所做的如下 在Java中是否有更好的方法可以做到这一点。
1回复

具有泛型类型参数的方法可以传递泛型类型参数

我的客户类别中有使用getter和setter的实例 但是当我试图通过时 它给我错误 为什么当我的收藏是CustomersDetails类型时,会这样呢?
2回复

接口中方法的java泛型类型参数

我想在这里实现的是由子类决定是否要将java.lang.String或java.util.HashMap作为参数传递给query()方法。 接口只需要声明子类必须实现查询方法,但我不关心什么类型的参数子类想要传入。 我有一个界面,如: 两个子类如: 然后我有一个工厂类来生
2回复

Java泛型类型参数

我很难让我的代码运行。 我有一个通用方法,应该对给定列表进行排序并删除所有重复项。 列表中的项目(例如String)均实现Comparable接口。 不幸的是,代码没有编译,我不明白为什么... 这就是我到目前为止所得到的。 为什么我不能对List<T>进行排序?
2回复

Java泛型类型参数

考虑以下代码: 现在我想要的是getDao能够实例化JsonDao和SqliteDao,但是通过扩展MyObject的类进行参数化,基本上是这样的: 类似的事情是否可能发生,还是类型擦除阻止了它?
1回复

Java泛型类型参数混乱

我创建了一个PriorityQueue,其中包含PeekingSortedIterators,如下所示: IteratorComparator比较PeekingSortedIterator基础的值。 我的代码如下: 我的问题如下: 为什么IteratorCompara
3回复

带有newInstance的java泛型类型参数

我不确定为什么Java要求我将makeInstance方法的返回强制转换为T? 我究竟做错了什么? 有没有更好的方法来实现这一目标?
2回复

Java泛型类型参数隐藏

我正在定义一个类: 编译器抱怨I被隐藏I 。 我想在第二时间I出现在定义的范围的第一个隐藏,仿佛可变I可以分配给两个不同的类型。 怎么做正确? 编辑: 这是一个内在阶级。 完整的代码可以是: 现在的问题是,如果我重新提名内部I到J ,我不确定I和J实际上是相同的