首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >方法签名和方法不同的擦除?

方法签名和方法不同的擦除?
EN

Stack Overflow用户
提问于 2013-05-22 11:04:56
回答 1查看 237关注 0票数 4

我遇到了一个例子,它表明在方法签名和方法上擦除是不同的,但是我不知道为什么/怎么做。JLS§8.4.8.3指出:

如果类型声明T有成员方法m1,并且存在在T中声明的方法m2或T的超类型,则这是一个编译时错误,使得以下所有条件都保持不变:

  1. m1和m2同名。
  2. m2可以从T.
  3. m1的签名不是m2签名的子签名(第8.4.2节)。
  4. m1或某些方法m1重写(直接或间接)的签名与m2或某些方法m2重写(直接或间接)的签名具有相同的擦除性。

编译时错误给出实例

代码语言:javascript
复制
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(字符串)对D是可访问的
  • D.id(对象)的签名不是C.id(字符串)的子签名。
  • 这两种方法具有相同的擦除效果。

前两点是显而易见的,但我不明白最后两点的解释。如果第三点成立,这两种方法怎么能有相同的擦除呢?从第三点看,似乎使用参数化类C的方法(即id(String)而不是id(T))删除签名。如果是这样的话,那么这两个方法应该有不同的擦除,但是这个例子表明方法擦除是在非参数化类上完成的。那么,擦除实际上是如何应用于方法签名和方法的呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-22 13:07:31

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

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

我尝试了一下,它让人困惑,但我想到了这样的解释:编译器不会擦除,而是替换泛型签名。因此,当D extends C<String>时,overriden 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将是有效的。显然,这是有可能的(虽然不是很有用):

代码语言:javascript
复制
class Foo<T> {
   public void set(final T thing) {}
}

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

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16690135

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档