为什么会发生以下情况:
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()
不会抛出错误。< / p>
答案 0 :(得分:6)
这可能是编译器错误。
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的子类型,或者R1可以通过未经检查的转换(第5.1.9节)转换为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
是R2
的子类型($ 4.10.2),因此返回类型是兼容的。 (但是,如果该理论是正确的,那么就不应该有“未经检查”的警告)
答案 1 :(得分:3)
方法function2
不是通用的。它返回Bar<Foo>
。
子类可以在重写方法中返回返回类型的子类。这称为协变返回类型。
但是Bar<F>
不是Bar<Foo>
的子类,即使F
子类Foo
- 泛型在Java中也不是协变的(但是数组)。
我的IDE实际上也警告我function1
:未选中覆盖:返回类型需要取消选中转换。我认为这只是一个警告,因为在基类和类型擦除中唯一存在泛型类型。我会说你无论如何都在非通用的Bar
上操作..
答案 2 :(得分:2)
<T extends Foo>
定义的类型T
必须是Foo
的某个子类型。这实际上并未在one
或two
中的任何位置使用。
我的猜测是因为编译器擦除函数类型的方式不同,因为有一个范围为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
进行编译:
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