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)在get
中突出显示Sub
作为下一条消息的编译错误:
'''中的'get()'与'超级'中的'get()'冲突;两种方法都有相同的擦除,但都不会覆盖另一种方法。
但是当我运行程序时,它编译并执行没有问题。我认为IntelliJ在分析代码时存在某种错误,Angelica在她的常见问题解答中说的是正确的。但我无法理解这一点。
答案 0 :(得分:1)
根据JLS,方法签名不包括返回类型,只包含方法名称及其参数类型。这意味着在编译Super和Sub时,编译错误应该返回,因为Sub.get()具有与Super.get()相同的擦除,但是既不覆盖也不重载Super.get()。它无法覆盖,因为有界类型X extends Number不是X类型的子类型,并且它不能重载,因为返回类型不是方法签名的一部分。在这种情况下,Sub.set会重载Super.set。
至于为什么你可以编译和运行它。如果您正在运行Java 6,那么Java 6中有一个已知的bug可以编译Super和Sub。在Java 7中,这是固定的,不允许使用。
答案 1 :(得分:0)
我认为public <S extends Number> S get()
的删除与public <T> T get()
的删除不同或协变。
编译并运行:
class B {
public <T> T get() {
return null;
}
}
class A extends B {
@Override
public <S> S get() {
return null;
}
这不是:
class B {
public <T> T get() {
return null;
}
}
class A extends B {
@Override
public <S extends Number> S get() {
return null;
}
答案 2 :(得分:0)
据我所知,为什么它重载而不是覆盖是因为编译器没有将它视为覆盖等效。进一步了解Angelika Langer常见问题解答,你会看到它讨论为什么覆盖一个方法不符合预期。
http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ051
总而言之,这些方法具有相同的名称和参数,但基于通用子类型被定义为不同。即使使用覆盖注释,编译器也会将其视为重载方法。在使用泛型时,方法有一个附加层,其中泛型类型作为方法的一部分应用,可以唯一地定义它。