[英]Java Generics and overridding
为什么会发生以下情况:
public class one{
public <T extends Foo> Bar<Foo> function1() {}
public Bar<Foo> function2(){}
}
public class two<F extends Foo> extends one{
public Bar<F> function1(){} //Doesn't throw an error
public Bar<F> function2(){} //Throws an error
}
通过说<T extends Foo>
我说Foo可以用超类型覆盖吗?
注意:我的问题不是为什么function2()
抛出错误...但为什么function1()
不会抛出错误。
这可能是编译器错误。
Two.function1
被认为是Two.function1
的首要方法的One.function1
来自http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2
签名
Two.function1
相同的签名的擦除One.function1
。
这是为了允许遗留子类型(Two)在超类型(One)被生成后仍然编译。
之后,javac需要检查返回类型:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.3
如果具有返回类型R1的方法声明d1覆盖或隐藏具有返回类型R2的另一个方法d2的声明,则对于d2,d1必须是return-type-substitutable(第8.4.5节),否则会发生编译时错误。
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.5
R1可以是R2的子类型,也可以通过未经检查的转换(第5.1.9节)将R1转换为R2的子类型,或者R1 = | R2 |
http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.9
从原始类或接口类型(第4.8节)G到表单G的任何参数化类型都有未经检查的转换。
未经检查的转换不适用于此处R1=Bar<F>, R2=Bar<Foo>
。 这就是为什么Javac报告function2
返回类型是冲突的。
Javac应该为function1
报告相同的错误。 我猜测在上一步中,javac删除了One.function1
,它是Bar function1()
,并错误地使用该版本来检查Two.function1
- 这里R2=Bar
,因此R1
是一个子类型($ 4.10) .2) R2
,因此返回类型是兼容的。 (但是,如果该理论是正确的,那么就不应该有“未经检查”的警告)
方法function2
不是通用的。 它返回一个Bar<Foo>
。
子类可以在重写方法中返回返回类型的子类。 这称为协变返回类型 。
但是Bar<F>
不是Bar<Foo>
子类,即使F
子类Foo
- 泛型在Java中不是协变的(但是数组也是如此)。
我的IDE实际上也警告我关于function1
: 未经检查的覆盖:返回类型需要未经检查的转换 。 我认为这只是一个警告,因为在基类和类型擦除中唯一存在泛型类型。 我会说你无论如何都要在非通用的Bar
上运行..
<T extends Foo>
定义了一个类型T
,它必须是Foo
某个子类型。 实际上并不是在one
two
地方使用one
。
我的猜测是因为编译器擦除函数类型的方式不同,因为有一个泛型类型定义作用于one.function1()
。
查看JLS 8.4.8.3定义了有效的方法覆盖。 关于“未经检查的转换”警告有一个例子。 在那里,它链接到8.4.5描述什么是“返回类型可替换”,并从那里链接到5.1.9关于未经检查的转换。
我没有答案,但似乎将该方法标记为通用方法(而不仅仅是使用参数化类型的方法)会触发允许未经检查的转换 - 无论是故意还是因为错误。
编辑:鉴于
public class Main {
class Bar<X> {}
class Foo{}
class one{
public <T extends Foo> Bar<Foo> function1() { return null; }
public Bar<Foo> function2(){ return null; }
}
class two<F extends Foo> extends one{
public Bar<F> function1(){ return null; } //Doesn't throw an error
public Bar<F> function2(){ return null; } //Throws an error
}
}
使用javac -Xlint:unchecked Main.java
进行javac -Xlint:unchecked Main.java
:
Main.java:9: warning: [unchecked] function1() in Main.two overrides <T>function1() in Main.one
public Bar<F> function1(){ return null; } //Doesn't throw an error
^
return type requires unchecked conversion from Main.Bar<F> to Main.Bar<Main.Foo>
where F,T are type-variables:
F extends Main.Foo declared in class Main.two
T extends Main.Foo declared in method <T>function1()
Main.java:10: error: function2() in Main.two cannot override function2() in Main.one
public Bar<F> function2(){ return null; } //Throws an error
^
return type Main.Bar<F> is not compatible with Main.Bar<Main.Foo>
where F is a type-variable:
F extends Main.Foo declared in class Main.two
1 error
1 warning
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.