[英]Java Generics with inheritance and covariance
在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
我们会在这里失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.