当前位置: 首页 > 知识库问答 >
问题:

当用非泛型方法覆盖泛型方法时,为什么子签名和未检查规则在返回类型上以这种方式工作?

况安然
2023-03-14
public class Base {

     <T> List<? extends Number>  f1()  {return null;}
     List<? extends Number>      f2()  {return null;}
     <T extends Number> List<T>  f3()  {return null; }
}

class Derived extends Base {

     List<String> f1() {return null;}   // compiles fine !!!
     List<String> f3() {return null; }  // compiles fine !!!

    // compile ERR: return type is incompatible with Base.f2()
     List<String> f2() {return null;}   
}

为什么在派生类中重写方法f1()和f3()的定义没有给出编译错误,就像在派生类中重写f2()方法的定义一样(它给出了编译错误返回类型与Base. f2()不兼容)?

JLS中的子签名重写规则允许重写方法(在派生类中)为非泛型,而重写方法(在基类中)为泛型。

未检查的覆盖规则允许在子类List中返回类型

但我无法解释下面的行为差异,我也不理解为什么f1()和f3()成功地重写了派生类编译中的定义(在Eclipse上,SE8),忽略了f3()的有界类型参数和f1()的有界通配符施加的限制!

另外,我的猜测-在派生编译器的f1()和f3()中,这两个方法都只返回“原始”列表-编译器进行擦除(目前仅在派生中!)首先,然后比较派生中的这些已擦除方法与基本中的未擦除(到目前为止)方法。现在,未检查的覆盖规则是确定的(并且不需要检查边界-这是完全不可能的),编译器决定这是正确的覆盖,并且编译继续进行。。。在Base中编译泛型的末尾。f1()和基。f3()也被删除:)

这个SO答案也为这个主题增加了一些想法。


共有1个答案

易淳
2023-03-14

您的f1f3重写不是泛型的,尽管原始声明是泛型的。编译允许覆盖的返回类型与原始返回类型不同,因为它们具有相同的类型擦除(List)。我认为这是JLS 8.4.5中的内容,尽管坦率地说,我觉得规范的这一部分有点混乱。

如果再次将替代更改为“常规”:

<T> List<String> f1() {return null;}
<T extends Number> List<String> f3() {return null; }

...然后两者都无法编译:

error: <T#1>f1() in Derived cannot override <T#2>f1() in Base
     <T> List<String> f1() {return null;}
                      ^
  return type List<String> is not compatible with List<? extends Number>
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>f1()
    T#2 extends Object declared in method <T#2>f1()

error: <T#1>f3() in Derived cannot override <T#2>f3() in Base
     <T extends Number> List<String> f3() {return null; }
                                     ^
  return type List<String> is not compatible with List<T#1>
  where T#1,T#2 are type-variables:
    T#1 extends Number declared in method <T#1>f3()
    T#2 extends Number declared in method <T#2>f3()

请注意,即使在原始代码中,javac也会对不安全的转换发出警告,如果使用-Xlint:unchecked,它会提供详细信息:

return type requires unchecked conversion from List<String> to List<? extends Number>
return type requires unchecked conversion from List<String> to List<T>
 类似资料:
  • 我想在我的android项目中自动转换视图。所以,我想重写 方法 方法但是java编译不允许这样做,但是重写的方法不会与父方法冲突,并且总是返回视图对象或其子对象。我发现了一些信息,java不允许用泛型方法重写非泛型方法,但我找不到解释。 http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ8

  • 我在覆盖接口中声明的方法时遇到了一些问题,该方法使用泛型参数作为其异常,并使用泛型作为其参数之一。为了说明,我编写了以下代码接口 通过javac运行,我得到 请注意,在接口中,metodoA和metodoB之间的唯一区别在于它们的参数。 为什么Implementadora(Implementadora)的metodoB(metodoB)(代码)不重写Interfaz(代码),但重写metodoB(

  • 我想说得具体一点。我有一个名为Result的类和一个名为Result的派生类 这些类在方法中用作返回类型。为此,我创建了这个helper类: 正如您所看到的,上面的代码对于成功有两种返回类型,一种是如果您不想返回任何东西,另一种是如果您想返回一些东西,但是失败的结果永远不会返回什么东西。这是不必要的,只是一个错误消息。这使我想到以下问题:当我想创建一个可以使用返回类型返回Success,而不使用返

  • 我有一个问题,从抽象类中重写泛型方法。 这是我的抽象类: 当我创建类(B)来实现类(a)时,如下所示: 显示了(getData)方法中的以下编译错误: ”“B。getData“(“字符串函数(字符串)”不是“a”的有效重写。getData'('字符串函数(类型)‘)。dart(无效覆盖) 以及返回语句中的此错误: 类型为“String”的值不能从方法'getData'返回,因为它的返回类型为'St

  • 我正在尝试理解使用以下代码得到的名称冲突错误: 错误消息: 错误:名称冲突:

  • 下面对getHighest()和getLowest()的调用返回Comparable类型的对象,而不是T类型的对象,这正是我们想要的。为什么,我该如何改进这段代码,使这些调用返回T(这样T的字段和方法就可用了)? 下一行生成编译器错误: 错误:找不到符号符号:方法getName()位置:接口java.lang.Comparable 我想employee.getHighest()返回一个员工(而不仅