Explanation of Java generic getthis technique
I'm reading about Java genetics. I'm a little confused when I encounter this topic
come from: http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205
public abstract class Node <N extends Node<N>> { private final List<N> children = new ArrayList<N>(); private final N parent; protected Node(N parent) { this.parent = parent; parent.children.add(this); // error: incompatible types } public N getParent() { return parent; } public List<N> getChildren() { return children; } } public class SpecialNode extends Node<SpecialNode> { public SpecialNode(SpecialNode parent) { super(parent); } }
Scroll down a few screens
public abstract class Node <N extends Node<N>> { ... protected Node(N parent) { this.parent = parent; parent.children.add( (N)this ); // warning: unchecked cast } ... }
Can someone give me an example to throw ClassCastException in the above code?
thank you.
Solution
First code example
In the first code example, there is a compilation error You can verify yourself in the IDE
I said: the method add (n) is in the list < n > type Not applicable to parameters (node < n >)
The problem is that n is a subtype of node The list of N may be the list of stupidnode, where stupidnode is a subclass of node However, the current instance may not be stupidnode, it may be a different subclass of node, so it may be wrong to add it
The second code example
Now the second code example is a developer who is tired of compile time errors he doesn't understand, thinks the compiler is wrong and tries to cast Such a cast will cause the code to compile, but may break under the same conditions at run time (as described above)
Therefore, the compiler issues warnings to help you understand that something may go wrong
Sample problem
For the previous two code examples, this problem may occur if code writing is called (for the two subclasses of node, NODEA and NodeB):
Node<NodeA> root = new NodeA<NodeA>(null); // code needs a change,to be able to handle the root,that has no parent // The line with parent.children will crash with a NullPointerException Node<NodeB> child = new NodeB<NodeB>(root);
In the second line, the code that will run in the constructor of node will be interpreted as (replacing the format parameter n with the current parameter NodeB):
public abstract class Node <NodeB> { private final List<NodeB> children = new ArrayList<NodeB>(); private final NodeB parent; protected Node(NodeB parent) { this.parent = parent; parent.children.add(this); // error: incompatible types } // ... }
As you can see, the caller's second line passes an instance of NODEA, and the constructor of node requires NodeB! So error
Update required by annotation: example code of subclass NODEA (or NodeB)
public class NodeA extends Node<NodeA> { public NodeA(NodeA parent) { super(parent); } }