虽然第一个示例确实进行了编译,但将给出未经检查的转换警告:
// Type safety: The return type List<?> for foo() from the type C needs// unchecked conversion to conform to List<String>public List<?> foo(){ return null;}
这里发生的事情是,通过声明类型的参数,
A.foo()并且
B.foo()是通用的方法。然后,覆盖
C.foo()忽略该类型参数。这类似于使用原始类型,本质上是“退出”该方法签名的通用类型检查。这会导致使用该继承的方法的编译器
擦除
代替:
List<String> foo()和
List<Integer> foo()二者成为
Listfoo(),其因此可以通过被实现
C.foo()。
您可以看到,通过将类型参数保留在
C.foo()声明中,将会出现预期的编译器错误:
// The return type is incompatible with A.foo()public <T> List<?> foo(){ return null;}
同样,如果两个接口方法中的任何一个都不声明类型参数,则从覆盖中省略类型参数将无法“选择退出”该方法的通用类型检查,并且返回类型
List<?>仍然不兼容。
JLS§8.4.2涵盖了此行为:
子签名的概念旨在表示两种方法之间的关系,这些方法的签名不完全相同,但是其中一个可以覆盖另一个方法。具体来说,它允许签名不使用泛型类型的方法覆盖该方法的任何泛化版本。这很重要,因此库设计者可以独立于定义库的子类或子接口的客户端自由地泛化方法。
Angelika
Langer的泛型常见问题解答在其部分中对此行为进行了扩展。非泛型方法可以覆盖泛型方法吗?:
现在,让我们探讨一个非泛型子类型方法覆盖泛型超类型方法的示例。如果签名的擦除相同,则将非通用子类型方法视为通用超类型方法的替代版本。
示例(非泛型子类型方法覆盖泛型超类型方法):
class Super { public <T> void set( T arg) { ... } public <T> T get() { ... }}class Sub extends Super { public void set( Object arg) { ... } // overrides public Object get() { ... } // overrides with unchecked warning}warning: get() in Sub overrides <T>get() in Super; return type requires unchecked conversionfound : Objectrequired: T public Object get() {在此,子类型方法具有签名,即
set(Object)和get(),与超级类型方法的擦除相同。这些类型擦除的签名被视为等效。该
get方法有一个缺陷:因为返回类型不是真正兼容的,所以我们收到未经检查的警告。亚型方法的返回类型get是Object,该超GET方法的返回类型是一个无限制类型参数。子类型方法的返回类型既不与超类型方法的返回类型相同,也不是其子类型。在这两种情况下,编译器都会欣然接受兼容的返回类型。而是子类型方法的返回类型Object可以通过未经检查的转换转换为超类型方法的返回类型。未经检查的警告表明,必须执行类型检查,编译器和虚拟机均不能执行该检查。换句话说,未检查的 *** 作不是类型安全的。如果是可转换的返回类型,则必须确保子类型方法的返回值与超类型方法的返回类型在类型上兼容,但是除程序员之外,没有人可以确保这一点。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)