具有继承性和协变性的Java泛型



在Java中使用泛型时,我很难理解如何正确使用协方差和通配符。

我尽量避免使用铸造。

这是我的情况:

class Element {}
class ChildElement extends Element {}
interface A<T> {
    T doSomething(T foo);
}
interface B extends A<Element> {}
interface C extends B {}
class D implements B {
    @Override
    public Element doSomething(Element foo) {} 
}
class E extends D implements C {
    @Override
    public Element doSomething(Element foo) {}
}

这种情况是可行的,但我希望能够为E类做这件事:

class E extends D implements C {
    @Override
    public ChildElement doSomething(ChildEment foo) {}
}

据我所见,我想做的是协方差,但在当前情况下我无法做到,因为我需要使用通配符。但我读到过,你不能用泛型和通配符来做协方差。

这个问题有什么解决办法吗?我希望保持每个类之间的强依赖关系。

谢谢你的帮助!

您必须使B通用,但您可以在通用参数上设置一个绑定,使其至少是Element:

interface B<T extends Element> extends A<T> {}
interface C<T extends Element> extends B<T> {}

那么你能得到的最接近的是:

 class D<T extends Element> implements B<T> {
    @Override
    public T doSomething(T foo) { return null;}
}
class E extends D<ChildElement> implements C<ChildElement> {
    @Override
    public ChildElement doSomething(ChildElement foo) { return null;}
}

其进行编译。

但我读到过,你不能用泛型和通配符。

这句话不是关于协变返回类型的,但它意味着你不能这样做:

List<Number> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
l1 = l2; //illegal

但它也是T的任何子类

interface Interface<T> {
    T method();
}
class SomeClass implements Interface<Number>{
    @Override
    public Float method() {
        return 1F;
    }
}

工作良好。但是子类(实现)和超类(接口)的方法签名必须匹配。所以在你的例子

class E extends D implements C {
    @Override
    public ChildElement doSomething(ChildEment foo) {}
}

这是违法的。

您所描述的接口不能是协变的。您希望/期望此代码发生什么?

class OtherElement extends Element{}
Element oe = new OtherElement();
E e = new E();
B b = e;
b.doSomething(oe);

这必须正确编译,但如果E#doSomething期望ChildElement,那么这里就会失败。

相关内容

  • 没有找到相关文章

最新更新