【发布时间】:2015-03-09 02:38:42
【问题描述】:
Angelica Langer 在她关于泛型的常见问题解答中说(请参阅Technicalities.FAQ822):
如果方法具有不同边界的类型参数,那么它们 不要覆盖,因为这些方法的签名不是 覆盖等效。请记住,类型参数边界是 泛型方法的签名。
示例(泛型子类型方法重载泛型超类型 方法;不推荐):
class Super { public <T> void set( T arg) { ... } public <T> T get() { ... } } class Sub extends Super { public <S extends Number > void set( S arg) { ... } // overloads public <S extends Number > S get() { ... } // overloads }
我不明白为什么get 方法在Sub 类中被重载。据我所知,这应该是编译时错误,因为get 在Sub 和Super 中具有相同的签名(返回类型不是其中的一部分)。
更让我困惑的是,我用来测试代码的 IDE (IntelliJ IDEA 14.0.3) 将Sub 中的get 突出显示为编译错误,并显示下一条消息:
'Sub' 中的 'get()' 与 'Super' 中的 'get()' 冲突;两种方法都有相同的擦除,但都不会覆盖另一个。
但是当我运行程序时,它编译并执行没有问题。我想 IntelliJ 在分析代码时存在某种错误,正确的是 Angelica 在她的常见问题解答中所说的。但我无法抓住重点。
【问题讨论】:
-
在 Eclipse 中,您可以将内置编译器设置为更严格,并将某些条件视为错误(例如赋值给 self 或通过实例访问静态方法)。我想在 IDEA 中也可以这样做。
-
问题出在被覆盖的方法的类型参数与超类方法的类型参数的界限不同。
-
正如您引用的帖子中所说,类型参数边界是泛型方法签名的一部分。所以
<T> T get()和<S extends Number > S get()有不同的签名。名字冲突仍然很糟糕,所以海报告诉它是不推荐 -
Kocko 的回答基本上得出结论,签名冲突并因此出现错误,但这不应该使它成为有效的覆盖吗?而且,如果类型参数边界是签名的一部分,那么它们是不同的,因此它不应该是有效的重载吗?我想回答/评论是什么让编译器说,“它既不是重载,也不是覆盖,因此是错误。”
-
@biziclop 这是一个完全有效的覆盖。覆盖方法的返回类型可以是被覆盖方法的返回类型的协变体(子类型)。