Java 具有继承和协变的泛型
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) {}
}
这种情况可行,但我希望能够为 class E :
执行此操作
class E extends D implements C {
@Override
public ChildElement doSomething(ChildEment foo) {}
}
据我所见,我想做的是协方差,但在目前的情况下我做不到,因为我需要使用通配符。但我读到你不能用泛型和通配符进行协变。
这个问题有什么解决办法吗?我想保持每个 classes 之间的强依赖性。
感谢您的帮助!
But I've read that you can't do covariance with generics and
wildcards.
这个声明不是关于协变return类型的,但是这意味着你不能这样做:
List<Number> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
l1 = l2; //illegal
但是T它也是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) {}
}
这是非法的。
您必须使 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;}
}
编译。
您描述的接口不能是协变的。您 want/expect 使用此代码会发生什么情况?
class OtherElement extends Element{}
Element oe = new OtherElement();
E e = new E();
B b = e;
b.doSomething(oe);
这编译正确,因为它必须 - 但如果 E#doSomething
预期 ChildElement
我们会在这里失败。
我很难理解在 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) {}
}
这种情况可行,但我希望能够为 class E :
执行此操作class E extends D implements C {
@Override
public ChildElement doSomething(ChildEment foo) {}
}
据我所见,我想做的是协方差,但在目前的情况下我做不到,因为我需要使用通配符。但我读到你不能用泛型和通配符进行协变。
这个问题有什么解决办法吗?我想保持每个 classes 之间的强依赖性。
感谢您的帮助!
But I've read that you can't do covariance with generics and wildcards.
这个声明不是关于协变return类型的,但是这意味着你不能这样做:
List<Number> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
l1 = l2; //illegal
但是T它也是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) {}
}
这是非法的。
您必须使 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;}
}
编译。
您描述的接口不能是协变的。您 want/expect 使用此代码会发生什么情况?
class OtherElement extends Element{}
Element oe = new OtherElement();
E e = new E();
B b = e;
b.doSomething(oe);
这编译正确,因为它必须 - 但如果 E#doSomething
预期 ChildElement
我们会在这里失败。