2017-10-29 26 views
5
public class Base { 

    <T> List<? extends Number> f1() {return null;} 
    List<? extends Number>  f2() {return null;} 
    <T extends Number> List<T> f3() {return null; } 
} 

class Derived extends Base { 

    List<String> f1() {return null;} // compiles fine !!! 
    List<String> f3() {return null; } // compiles fine !!! 

    // compile ERR: return type is incompatible with Base.f2() 
    List<String> f2() {return null;} 
} 

为什么覆盖方法F1()和派生类F3()的定义,得到没有编译错误,如在派生类(其给出编译错误“返回类型重写F2()方法的定义与基本不相容。 f2()“)?当使用非泛型方法重写泛型方法时,为什么副标记和未检查的规则在返回类型上以这种方式工作?

JLS中的子签名覆盖规则允许覆盖方法(在Derived类中)是非泛型的,而覆盖方法(在Base类中)是泛型的。

未经检查的覆盖规则允许在子类List<String>中生成返回类型,而不是基类中的List<T>

但我无法解释下面的行为差异,我不明白为什么f1()和f3()覆盖Derived类中的定义已成功编译(在Eclipse,SE8上),忽略了有界类型参数f3()和有界通配符f1()

P.S.我的猜测 - 在Derived编译器中的f1()和f3()中,将这两种方法视为仅返回“raw”。List - 编译器首先进行擦除(此时仅在Derived !?中),然后将Derived中的这些擦除方法与未擦除(到目前为止)在Base中的方法。现在未检查覆盖规则是可以的(并且不需要检查边界 - 它根本不可能),编译器决定这是正确的覆盖并且编译进一步...以及Base.f1()和Base中编译泛型末尾的某处.f3()也删除:)))

This SO answer也增加了这个主题的想法。

回答

3

您的f1f3覆盖不是通用的,尽管最初的声明是通用的。编译允许覆盖的返回类型与原始返回类型不同,因为它们具有相同类型的擦除(List)。我认为JLS 8.4.5后面,虽然坦率地说,我觉得这部分规范有点混淆。

如果你改变了覆盖再次成为通用:

<T> List<String> f1() {return null;} 
<T extends Number> List<String> f3() {return null; } 

...那么这两个无法编译:

error: <T#1>f1() in Derived cannot override <T#2>f1() in Base 
    <T> List<String> f1() {return null;} 
        ^
    return type List<String> is not compatible with List<? extends Number> 
    where T#1,T#2 are type-variables: 
    T#1 extends Object declared in method <T#1>f1() 
    T#2 extends Object declared in method <T#2>f1() 

error: <T#1>f3() in Derived cannot override <T#2>f3() in Base 
    <T extends Number> List<String> f3() {return null; } 
            ^
    return type List<String> is not compatible with List<T#1> 
    where T#1,T#2 are type-variables: 
    T#1 extends Number declared in method <T#1>f3() 
    T#2 extends Number declared in method <T#2>f3() 

注意,即使在你的原代码,javac发出警告左右不安全的转换,如果您使用-Xlint:unchecked它提供了详细信息:

return type requires unchecked conversion from List<String> to List<? extends Number> 
return type requires unchecked conversion from List<String> to List<T> 
相关问题