【问题标题】:Compilation error when overriding a generic method with a type parameter使用类型参数覆盖泛型方法时出现编译错误
【发布时间】:2019-06-08 17:36:16
【问题描述】:

我知道类型擦除,但这对我来说没有意义。

class Base{
   public <T> Collection<T> transform(Collection<T> list)
   { 
      return new ArrayList<T>(); 
   }
} 

public class Derived extends Base {
    @Override // compilation error
    public Collection<CharSequence> transform(Collection<CharSequence> list) {
        return new HashSet<CharSequence>();
    }
}

在我的 IDE 中产生了一个错误:

'Derived' 中的

'transform(Collection)' 与 '基础'中的'转换(集合)';两种方法都有相同的擦除, 但两者都不会覆盖另一个

我的想法是我们可以覆盖 transform 而不会出现编译器错误。 为什么Derived 中的transform 没有正确覆盖Base 中的transform 方法?我知道这与类型擦除有关,但是。我不明白为什么。

【问题讨论】:

  • 需要给Base同样的泛型参数T,然后在Derived中指定具体参数。
  • 这是不允许的!如果允许,可以使用以下代码:Base instance = new Derived(); Collection&lt;Number&gt; numbers = ...; Collection&lt;Number&gt; transformed = instance.transform(numbers); 但正如您所见,您会使用错误的参数调用派生类的转换方法。
  • 您在基类中的方法签名表明它允许any T,而不是特定的T。

标签: java generics overriding


【解决方案1】:

基类中方法的签名:

<T> Collection<T> transform(Collection<T> list)

说“我将接受一个包含 any 类型元素的集合,并返回给你一个相同类型元素的集合。

根据 Liskov 替换原则,任何实现此方法的子类都必须这样做。特别是,它必须接受包含任何类型元素的集合。

如果您尝试使用方法覆盖它:

Collection<CharSequence> transform(Collection<CharSequence> list)

那么它就不会做需要做的事情:它不接受任何类型的集合元素,它只接受特定类型的元素。因此它不会覆盖超类方法

通常,在子类中定义一个不覆盖超类中的方法的方法是没有问题的:您可以在子类中定义超类中不存在的新方法。但是由于类型擦除,您不能继续使用这两种方法,因为它们具有相同的签名。因此,编译器不允许您这样做。

【讨论】:

    【解决方案2】:

    BaseDerived 不是泛型类,Base 中的 Collection&lt;T&gt;Derived 中的 Collection&lt;CharSequence&gt; 无关 - 它们之间没有联系 - 因此出现错误!

    您可以按如下方式修复它:

    class Base<T> {
        public Collection<T> transform(Collection<T> list) {
            return new ArrayList<>();
        }
    }
    
    class Derived extends Base<CharSequence> {
        @Override
        public Collection<CharSequence> transform(Collection<CharSequence> list) {
            return new HashSet<>();
        }
    }
    

    否则,有效的覆盖将是:

    class Derived extends Base {
        @Override
        public <T> Collection<T> transform(Collection<T> list) {
            return new HashSet<>();
        }
    }
    

    【讨论】:

    • 而且,如果你愿意,你也可以在Derived 中设置返回类型HashSet&lt;CharSequence&gt;,因为这是协变的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    相关资源
    最近更新 更多