使用抽象中的通用参数覆盖方法 Class

Overriding Method with Generic Parameters from Abstract Class

我无法编译需要覆盖抽象 class 超类型方法的方法,该超类型使用泛型作为其中一个参数。编译器抱怨扩展 class' setRef() 方法没有覆盖超类型的方法。

父摘要Class:

public abstract class AbsClass<Q extends Interf> {
    public abstract Ref<? extends AbsClass<Q>> getRef();
    public abstract <M extends AbsClass<Q>> void setRef(Ref<M> newRef);
}

参考是:

public interface Ref<M extends AbsClass<? extends Interf>> { }

Interf 是:

public interface Interf { }

扩展子 Class(setRef() 不编译):

public class ChildClass extends AbsClass<InterfImpl> {
    @Override
    public Ref<ChildClass> getRef() {
        return null;
    }

    @Override
    public <M extends ChildClass> void setRef(Ref<M> newRef) {
        return null;
    }
}

我也尝试过使用通配符,但收到了同样的错误。使用通配符,抽象 class' setRef() 是:

public abstract void setRef(Ref<? extends AbsClass<Q>> newRef);

扩展 class' setRef() 是:

public void setRef(Ref<ChildClass> newRef)

甚至:

public void setRef(Ref<? extends ChildClass> newRef)



我能让它编译的唯一方法是扩展 class' setRef() 使用抽象 class' 类型:

public <M extends AbsClass<Interf>> void setRef(Ref<M> newRef)

但我想将 newRef 参数的类型限制为 Ref<ChildClass> 或子类型,因此这并不完美。如何让我的扩展 class 只允许 ChildClass 或其子类型用于 setRef() 方法的 newRef 参数?我的部分困惑是 ChildClass' getRef() return 值可以很好地处理通用类型,而 setRef() 参数上的相同 "signature" 无法编译。帮助?谢谢!

您遇到错误,因为在 AbsClass.setRef() 中,您的参数类型为 Ref<? extends AbsClass<Q>>

但是在你的 ChildClass.setRef() 中,参数的类型是 Ref<? extends ChildClass>

对于重写,子类在方法中的类型参数应与其父类相同(在使用泛型时进行类型擦除之前)。

setRef 的问题是您可以通过类型 AbsClass<? extends Interf> 的变量访问 ChildClass 的实例,因此 setRef 的参数类型看起来像<M extends AbsClass<? extends Interf>> 又可以是任何 M 但也不匹配 <M extends AbsClass<Q>> 因为 Q 在您的情况下被定义为 InterfImpl

您可以将 ChildClass 更改为:

public <M extends AbsClass<InterfImpl>> void setRef(Ref<M> newRef)

但这仍然允许任何 M 并且你不能只使用 Ref<ChildClass> 因为我上面说的,即编译器不会知道 Ref<ChildClass> 如果你使用AbsClass<InterfImpl> 甚至 AbsClass<? extends InterfImpl>.

类型的变量

仅允许 ChildClass 参数的一种方法是在泛型类型中也使用 ChildClass,例如像这样:

public abstract class AbsClass<Q extends Interf, M extends AbsClass<Q, M>> {
  public abstract Ref<M> getRef();
  public abstract void setRef(Ref<M> newRef);
}

public class ChildClass extends AbsClass<InterfImpl, ChildClass> {

  public Ref<ChildClass> getRef() { return null; }

  public void setRef(Ref<ChildClass> newRef) { }
}