Java泛型和重写

时间:2013-09-05 19:46:44

标签: java generics

为什么会发生以下情况:

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>

3 个答案:

答案 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,因此R1R2的子类型($ 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的某个子类型。这实际上并未在onetwo中的任何位置使用。

我的猜测是因为编译器擦除函数类型的方式不同,因为有一个范围为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