擦除方法签名和方法有何不同?

时间:2013-05-22 11:04:57

标签: java jls

我遇到了一个示例,表明在方法签名和方法上擦除的方式不同,但我不知道为什么/如何。 JLS §8.4.8.3州:

  

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

     
      
  1. m1和m2具有相同的名称。
  2.   
  3. m2可从T。
  4. 访问   
  5. m1的签名不是m2签名的子签名(§8.4.2)。
  6.   
  7. m1的签名或某些方法m1覆盖(直接或间接)具有与m2的签名相同的擦除或某种方法m2覆盖(直接或间接)。
  8.   

编译时错误example given

class C<T> {
    T id (T x) {...}
}
class D extends C<String> {
    Object id(Object x) {...}
}

解释:

  

这是非法的,因为D.id(Object)是D的成员,C.id(String)以D的超类型声明,并且:

     
      
  • 这两个方法具有相同的名称,id
  •   
  • C.id(String)可供D
  • 访问   
  • D.id(Object)的签名不是C.id(String)
  • 的签名   
  • 这两种方法具有相同的擦除
  •   

前两点很明显,但我不明白解释的最后两点。如果第三点成立,这两种方法如何具有相同的擦除?从第三点来看,似乎使用参数化类C&lt; String&gt;的方法(即id(String)而不是id(T))完成签名的擦除。如果是这种情况,那么这两种方法应该有不同的擦除,但是该示例表明方法擦除是在非参数化类上完成的。那么,如何在方法签名和方法上实际应用擦除?

1 个答案:

答案 0 :(得分:2)

擦除意味着所有通用类型T(在C情况下为String)的出现都被Object(+所需类型转换)替换。由于类型信息以这种方式丢失,因此示例中存在冲突 - JVM无法决定调用哪种方法。

编辑(这是错误的) afaik :子签名是接受兼容类型(例如超类型String)和/或返回协变类型的方法。

我尝试了它并且令人困惑,但是得出了这样的解释:编译器不会擦除,而是替换通用签名。因此,当D extends C<String>覆盖C<String>.id的签名变为:String id(String x)时。显然,D的方法id具有不同的签名,也没有相同的删除(因为String不是通用类型)。因此,D.id的签名不是C的子签名。 (符合规则3)

另一方面,C<T>.id(T x)的删除为Object id(Object x),与D.id(Object x)的删除相同。 (符合规则4)

在此之后,如果可以保持签名和删除对齐,则覆盖id是有效的。显然这是可能的(虽然不是很有用):

class Foo<T> {
   public void set(final T thing) {}
}

class Bar<T> extends Foo<T> {
   @Override
   public void set(final Object thing) {}
}

这在没有警告的情况下编译eclipse。