Posted under Java
Permalink
Tags Generics, Gotcha, Tip, Tutorial
Update 7/12/22
Previously I have implemented a composite iterator for iterating a tree of tags from a search on a PropertyTree implementation. Note that in this case, the abstract base class for the composites was a TagTree, and the concrete subclasses were a TagList and a Tag. As a Tag did not need a list, the list of children was in the concrete TagList and not the TagTree. Therefore, the TagTree did not need to have generic references to self referential subtypes in the way the example below does – in fact it did not need to be generic at all. Therefore it did not suffer this problem. For further clarity see the example below from Angelika Langer here. In her code, the list is in the abstract superclass which is why it suffers the problem below and potentially needs the infamous getThis trick per below.
Original Post
Some generic classes are recursively self-referential, such as in the following abstract class statement for a tree node :-
public abstract class Node <N extends Node<N>> {
…
}
In this situation it is sometimes necessary for example to pass a reference to this from the superclass to a specific subclass which expects an argument of type N :-
public void methodA(N node) {
//do something with the passed node
}public void methodB(N node) {
node.methodA(this); // error – incompatible types
}
In the above fragment, the error is because this in the superclass has a type of Node<N> which does not match N.
Another related use case is where a fluent API returns a ‘this’ reference from each of the fluent methods. If for example a fluent method in an abstract base class needs to return a ‘this’, as above the reference needs to be for the concrete subclass so the same problem occurs.
The topic is discussed in detail in Java Generics and Collections, section 9.4 on the Strategy pattern. The section from the book may be viewed online at Flylib here.
Angelika Langer also discusses it in more detail her Generics FAQ here
In the above case, the problem can be solved with the so-called getThis trick. An abstract getThis method is defined in the superclass, and implemented in each subclass:-
Superclass
protected abstract N getThis();
Subclass
protected Subtype getThis() {return this}; // where Subtype is the concrete subtype of N
Now the superclass can obtain a type correct reference to this and pass it without error:-
public void methodB(N node) {
node.methodA(getThis()); // this time it works
}
As Angelika Langer points out in her examples, there can be other ways around this kind of problem depending on the situation, but sometimes you do need the getThis trick.