I found I can't call generic methods of wildcard types and don't understand why?
public class GenericsTry2 {
public static class Element {
private Container<? extends Element> container;
public Container<? extends Element> getContainer() {
return container;
}
public void setContainer(Container<? extends Element> container) {
this.container = container;
}
public void doStuff() {
getContainer().doStuff(this); // how to call this?
}
}
public static class SomeSubElement extends Element {
}
public static class SomeSubElement2 extends Element {
}
public static class Container<E extends Element> {
public void doStuff(E element) {
}
}
public static void main(String[] args) {
Container<SomeSubElement2> c = new Container<SomeSubElement2>();
Element e = new SomeSubElement();
c.doStuff((SomeSubElement2) e); // still can do this at compile time this way
}
}
Having Container<? extends Element>
means that the Container
can only produce Element
(s), but cannot consume Element
(s).
The reason for this is that ? extends Element
denotes a whole family of unknown sub-types of Element
. Let's assume you set your container to Container<SomeSubElement>
. Then, passing this
to the container (even you know it's an Element
, or a sub-type of Element
) won't be correct, because this
may be or may not be SomeSubElement
(depends on the Runtime type).
In the world of Generics, this is called co-variance.
In order to have the code compiling (I don't guarantee that you need exactly this), you can do (note that I've changed the container to be consumer of Element
(s), instead of producer):
public class Element {
private Container<? super Element> container;
public Container<? super Element> getContainer() {
return container;
}
public void setContainer(Container<? super Element> container) {
this.container = container;
}
public void doStuff() {
getContainer().doStuff(this);
}
}
However, if you need your Container
to be a producer and a consumer at the same time, just get rid of the wildcard and parameterize it with <Element>
only.
Container<E extends Element>
means that it contains something E
that extends from Element
. Not necessarily the Element
itself.
Imagine what would happen if you'll have:
Container<RedElement> redElements = new Container<RedElement>();
Container<E extends Element> container = redElements;
// According to your logic it will work
container.add(new Element());
// Problem here. You just put Element there which is not RedElement.
RedElement element = container.getFirst();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With