在Java中重写泛型集合时出错

在Java中重写泛型集合时出错,java,generics,inheritance,overriding,Java,Generics,Inheritance,Overriding,当我试图重写一个采用列表的方法时,我得到了以下编译错误 此行有多个标记: -类型为child的方法getname(List)必须重写或实现超类型方法 -名称冲突:类型为child的方法getname(List)与类型为parent的方法getname(List)具有相同的擦除,但不覆盖它 我的印象是,由于擦除,采用列表的方法和采用列表的子类方法将被视为被覆盖,因为这两种方法的签名在擦除后是相同的 是涉及擦除的方法签名的定义。 我不明白为什么会出现这个错误,它到底意味着什么 我的代码如下: cla

当我试图重写一个采用
列表的方法时,我得到了以下编译错误

此行有多个标记:
-类型为
child
的方法
getname(List)
必须重写或实现超类型方法
-名称冲突:类型为
child
的方法
getname(List)
与类型为
parent
的方法
getname(List)
具有相同的擦除,但不覆盖它

我的印象是,由于擦除,采用
列表
的方法和采用
列表
的子类方法将被视为被覆盖,因为这两种方法的签名在擦除后是相同的

是涉及擦除的方法签名的定义。
我不明白为什么会出现这个错误,它到底意味着什么

我的代码如下:

class parent {

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

}

class child extends parent {

    @Override  // here is the compile error
    public void getname(List<Integer> num) {
        System.out.printf("child class: %s",num);
    }
}
类父类{
public void getname(列表编号){
System.out.printf(“父类:%s”,num);
}
}
类子级扩展父级{
@Override//这里是编译错误
public void getname(列表编号){
System.out.printf(“子类:%s”,num);
}
}

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

错误消息非常清楚:它具有相同的擦除,但类型不匹配,因此不被视为重写。
列表
不是
列表
;它既不能将其视为覆盖(要求类型完全匹配),也不能将其视为重载(要求擦除不同)。

为了补充这里已经给出的答案,我想对
方法的签名在擦除后是相同的进行评论。。。但是编译器会在擦除之前检查方法类型

您可以创建一个“不同的”父类,例如

class Parent {
  public void getname(List<Integer> num) {
    System.out.printf("child class: %s",num);
  }
}
类父类{
public void getname(列表编号){
System.out.printf(“子类:%s”,num);
}
}
,编译它,使用它编译
子类
类,然后在同一JVM中无问题地混合原始的
父类
子类
,避免编译器检查和使用类型擦除


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

基本上你的印象是错误的,这是不可能的。联合联络小组认为这是特别非法的

发件人:

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

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

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

当m1是m2的子签名或m2是m1的子签名时,两个方法签名m1和m2是覆盖等价的

加粗的位很重要,因为它没有说“m1的擦除与m2的擦除相同”。它实际上允许这样做(以及一些更复杂的例子):

A类{
无效进程(列表){}
}
B类扩展了A类{
@凌驾
无效进程(列表){}/|列表|是对列表的擦除
}
由于
B.process
的方法签名是
A.process
的擦除,因此它是一种覆盖

根据,OP中的示例可能是重载,因为签名不是等效的:

如果一个类的两个方法。。。如果具有相同的名称,但签名不是重写等效的,则称方法名称重载

除了这是一个编译时错误():

如果类型声明T有一个成员方法m1,并且存在一个在T或T的超类型中声明的方法m2,从而满足以下所有条件,则这是编译时错误:

  • m1和m2具有相同的名称

  • m2可从T进入

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

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

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


您指出的错误显然是由于@Override注释造成的。在验证注释时(我认为必须在编译过程的早期阶段进行),没有发生类型擦除。因此,类型列表与列表不同,您会得到警告。但即使没有注释,我也会出错

    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{`. 
name clash:child中的getname(java.util.List)和parent中的getname(java.util.List)具有相同的擦除,但两者都不重写另一个
类子级扩展父级{`。
这个错误清楚地表明,它们具有相同的擦除,但仍然没有超越,所以Java原则上不允许这样做。
我可以理解,如果允许的话,它会导致许多问题/混乱。例如,如果有人打电话
new Child()。get_name(new List())
,它无法解析为子方法,这将打破过度使用的概念。因此,不允许这样做是正确的。

可能是相同的擦除,但它仍然违反编译时类型安全,因此您不能这样做。由于擦除,类型信息丢失正确?因此,类型匹配如何重要?在字节码l伊芙,现在的信息是正确的吗?@user198887
    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{`.