方法与类型中的另一种方法具有相同的擦除
为什么在同一个班级中使用这两种方法是不合法的?
class Test{
void add(Set<Integer> ii){}
void add(Set<String> ss){}
}
我收到compilation error
方法add(Set)与Test类型中的另一种方法具有相同的擦除添加(Set)。
虽然我可以解决它,但我想知道为什么javac不喜欢这样。
我可以看到,在很多情况下,这两种方法的逻辑非常相似,可以用一个单一的方法取代
public void add(Set<?> set){}
方法,但情况并非总是如此。
如果你想让两个constructors
接受这些参数,这是非常烦人的,因为那样你就不能只改变一个constructors
的名字。
此规则旨在避免使用原始类型的遗留代码中的冲突。
这里有一个为什么不允许的例子,来自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>)
方法。 但是,当然,编译器需要解决一个方法。 为了消除这种不明确性,类不允许有多个与override等效的方法 - 也就是说,擦除后具有相同参数类型的多个方法。
关键是这是一种语言规则,旨在保持与使用原始类型的旧代码的兼容性。 这不是擦除类型参数所要求的限制; 因为方法解析发生在编译时,所以将通用类型添加到方法标识符就足够了。
Java泛型使用类型擦除。 尖括号( <Integer>
和<String>
)中的位被移除,所以你最终会得到两个具有相同签名的方法(你在错误中看到的add(Set)
)。 这是不允许的,因为运行时不会知道每个案例使用哪一个。
如果Java获得了泛化的泛型,那么你可以做到这一点,但现在可能不太可能。
这是因为Java泛型是通过Type Erasure实现的。
你的方法在编译时会被翻译成如下形式:
方法解析发生在编译时,不考虑类型参数。 (见埃里克森的答案)
void add(Set ii);
void add(Set ss);
两种方法都具有相同的签名而没有类型参数,因此是错误的。
链接地址: http://www.djcxy.com/p/73417.html