覆盖Java中的泛型集合时出错

时间:2014-02-10 23:05:55

标签: java generics inheritance override

当我尝试覆盖采用List<String>的方法时,我得到以下编译错误

  

此行有多个标记:
   - 类型getname(List<Integer>)的方法child必须覆盖或实现超类型方法
   - 名称冲突:getname(List<Integer>)类型的方法child与类型getname(List<String>)的{​​{1}}具有相同的删除权,但不会覆盖它

我的印象是,由于 erasure ,采用parent的方法和采用List<String>的子类方法将被视为重写,因为擦除后两种方法的签名相同。

Here方法签名的定义,涉及擦除
我不明白为什么会出现这个错误,究竟是什么意思。

我的代码如下:

List<Integer>

5 个答案:

答案 0 :(得分:3)

List<String>List<Integer>是不同的类型,getname(List<String> num)getname(List<Integer> num)是具有不同签名的方法。所以第二个不会覆盖第一个。因此child无法扩展parent此方法。

答案 1 :(得分:3)

错误消息非常清楚:它具有相同的擦除,但类型不匹配,因此它不被视为覆盖。 List<Integer>不是List<String>;它不能将它视为覆盖(这将要求类型完全匹配)或重载(这将要求删除不同)。

答案 2 :(得分:3)

基本上你的印象不正确,这是不可能的。 JLS认为这是非法的。

来自8.4.2

  

方法m1的签名是方法m2的签名的子签名,如果:

     
      
  • m2与m1具有相同的签名,或

  •   
  • m1的签名与m2的签名的删除(§4.6)相同。

  •   
     

如果m1是m2的子签名或m2是m1的子签名,则两个方法签名m1和m2是覆盖等价的。

强化位很重要,因为它说“m1的擦除与m2的擦除相同”。它实际上允许的是这个(以及一些更复杂的例子):

class A {
    void process(List<String> list) {}
}
class B extends A {
    @Override
    void process(List list) {} // |List| is erasure of List<T>
}

由于B.process的方法签名是A.process的删除,因此它是一种覆盖。

根据8.4.9,OP中的示例可能是一个重载,因为签名不是覆盖等价的:

  

如果类的两个方法具有相同的名称但签名不是覆盖等效的,那么方法名称就会被重载。

除了它特别是编译时错误(8.4.8.3):

  

如果类型声明T具有成员方法m1并且存在以T形式声明的方法m2或T的超类型以使得满足以下所有条件,那么这是编译时错误:

     
      
  • m1和m2具有相同的名称。

  •   
  • m2可从T。

  • 访问   
  • m1的签名不是m2签名的子签名(§8.4.2)。

  •   
  • m1的签名或某些方法m1覆盖(直接或间接)具有与m2的签名相同的擦除或某种方法m2覆盖(直接或间接)。

  •   
     

这些限制是必要的,因为泛型是通过擦除实现的。上面的规则意味着在同一个类中声明的具有相同名称的方法必须具有不同的擦除。 ...

答案 3 :(得分:0)

要添加到此处已有的答案,我想对the signature of the methods is the same after erasure进行评论......但编译器会在擦除前检查方法类型。

您可以执行类似创建“不同”Parent类的操作,例如

class Parent {
  public void getname(List<Integer> num) {
    System.out.printf("child class: %s",num);
  }
}

,编译它,用它来编译Child类,然后将原始的Parent.classChild.class混合在同一个JVM中,没有问题,避免编译器检查和使用类型擦除。

但只要编译器注意到“在同一次运行中”做类似的事情,它就会因为Ashot和Louis解释的原因而失败。

答案 4 :(得分:0)

您指出的错误显然是因为@Override注释。验证注释(我认为必须在编译过程的早期阶段发生)时,类型擦除尚未发生。因此List类型与List不同,您会收到警告。但即使没有这个注释,我也会收到错误

    name clash: getname(java.util.List<java.lang.Integer>) in child and getname(java.util.List<java.lang.String>) in parent have the    same erasure, yet neither overrides the other
class child extends parent{`. 

这个错误明确表示他们有相同的擦除但仍然没有超过骑行。所以Java原则上不允许它。 我可以理解,如果允许,它会导致许多问题/混淆。对于例如如果有人拨打电话new Child().get_name( new List<String> () ),则无法解决Child方法,这会打破过度骑行的概念。所以不允许这是正确的。