繁体   English   中英

Java泛型和覆盖

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM