简体   繁体   English

具有继承和协方差的Java泛型

[英]Java Generics with inheritance and covariance

I'm having a bit of a hard time to understand how to correctly use covariance and wildcards when using generics in Java. 在Java中使用泛型时,我有点难以理解如何正确使用协方差和通配符。

I'm trying to avoid having to use casting. 我试图避免使用铸造。

Here's my situation : 这是我的情况:

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) {}
}

This situation works, but I would like to be able to do this instead for class E : 这种情况有效,但我希望能够为E类做到这一点:

class E extends D implements C {

    @Override
    public ChildElement doSomething(ChildEment foo) {}
}

From what I've seen, what I want to do is covariance, but I can't do it in the current sitution as I need to use wildcards. 从我所看到的,我想要做的是协方差,但我不能在当前的情况下这样做,因为我需要使用通配符。 But I've read that you can't do covariance with generics and wildcards. 但我读过你不能对泛型和通配符做协变。

Is there any solution to this problem ? 有没有解决这个问题的方法? I'd like to keep the strong dependencies between each classes. 我想保持每个类之间的强大依赖关系。

Thanks for your help ! 谢谢你的帮助 !

You have to make B generic, but you can put a bound on the generic parameter such that it's at least an Element : 你必须使B泛型,但你可以在泛型参数上设置一个绑定,使它至少是一个Element

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

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

Then about the closest you can get is: 然后你可以得到的最近的是:

 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;}
}

which compiles. 编译。

But I've read that you can't do covariance with generics and wildcards. 但我读过你不能对泛型和通配符做协变。

This statement is not about covariant return type, but it means that you can't do this: 此声明不是关于协变返回类型,但它意味着您不能这样做:

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

But T it's also any subclass of T. So thing like this: 但它也是T的任何子类。所以这样的事情:

interface Interface<T> {
    T method();
}

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

works fine. 工作良好。 But method's signature of subclass(implementation) and superclass(interface) must matches. 但是方法的子类(实现)和超类(接口)的签名必须匹配。 So in your example 所以在你的例子中

class E extends D implements C {

    @Override
    public ChildElement doSomething(ChildEment foo) {}
}

it's illegal. 这是非法的。

The interface you've described can't be covariant. 您描述的界面不能协变。 What would you want/expect to happen with this code? 您希望/期望在此代码中发生什么?

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

This compiles correctly, as it must - but if E#doSomething expected a ChildElement we would have a failure here. 这正确编译,因为它必须 - 但如果E#doSomething期望ChildElement我们会在这里失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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