9

为什么会发生以下情况:

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() 引发错误。

4

3 回答 3

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

这是为了允许在超类型(一)被泛化后,遗留子类型(二)仍然可以编译。

之后,javac 需要检查返回类型:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.3

如果具有返回类型 R1 的方法声明 d1 覆盖或隐藏具有返回类型 R2 的另一个方法 d2 的声明,则 d1 必须是 d2 的返回类型可替换(第 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是 的子类型($4.10.2)R2,因此返回类型是兼容的。(但是,如果该理论是正确的,则不应出现“未经检查”的警告)

于 2013-09-05T21:16:45.083 回答
3

该方法function2不是通用的。它返回一个Bar<Foo>.

子类可以在被覆盖的方法中返回返回类型的子类。这称为协变返回类型

ButBar<F>不是 的子类Bar<Foo>,即使F子类Foo- 泛型在 Java 中不是协变的(尽管数组是)。


我的 IDE 实际上也警告我function1Unchecked overriding: return type requires unchecked conversion。我相信这只是一个警告,因为基类和类型擦除中唯一存在泛型类型。我会说您在这里无论如何都在使用非泛型Bars 进行操作..

于 2013-09-05T20:03:47.340 回答
2

<T extends Foo>定义一个类型,该类型T必须是 的某个子类型Foo。这实际上并没有在oneor中的任何地方使用two

我的猜测是这是因为编译器如何擦除函数的类型的处理方式不同,因为有一个泛型类型定义范围为one.function1().

查看JLS 8.4.8.3定义了有效的方法覆盖。有一个关于“未经检查的转换”警告的例子。在那里,它链接到8.4.5描述什么是“return-type-substitutable”,并从那里链接到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
于 2013-09-05T20:08:19.050 回答