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);
   }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>