I am having a problem with the Visitor pattern and generics. I have some abstract class whose children are to be visited. Look at this code:
public abstract class Element extends SomeSuperClass {
public void accept(Visitor<? extends Element> v) {
v.visit(this);
}
}
public interface Visitor<T extends SomeSuperClass> {
void visit(T element);
}
So the idea is: I have some class hierarchy (e.g. Element is a subclass of SomeSuperClass).
I have got some generic Visitor interface to visit this hierarchy. Now in the middle of this hierarchy is the Element class, which is abstract and has it’s own subclasses.
Now I want Element to accept all visitors of its subclasses, which is why I put this line:
public void accept(Visitor<? extends Element> v)
But now I am receiving error:
The method visit (
capture#1-of ? extends Element) in the typeVisitor<capture#1-of ? extends Element>is not applicable for the arguments (Element).
I understand that ? extends Element is not Element. My question is: Can I express my idea in a different way? Or I have just missed the idea of generics in this case?
Note that
Tin<T extends SomeSuperClass>can be a type completely unrelated toElementand the compiler must ensure for the general case thatvisit(T t)will work for every possibleT.The code you have calls
Visitor.visit(Element e), but the visitor in question could beVisitor<SubElement>. That wouldn’t make sense.I think that the requirement “
Elementmust accept all visitors of its subclasses” doesn’t make sense: the visitor must at least be able to visitElementand all its subclasses. That would be aVisitor<Element>.The construct
accept(Visitor<? extends Element> v)means thatvcan be any suchVisitor<T>thatT extends Element. It does not mean that the visitor itself will be of the typeVisitor<? extends Element>. In fact, no such thing even exists in Java. Every Visitor will have a specific type parameter associated with it, not a wildcard.