7

私はJavaGenericsについて読んでいて、少し混乱しているこのトピックに出くわしました。

差出人: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);
   }
} 

いくつかの画面を下にスクロールします...

public abstract class Node <N extends Node<N>>  {
   ...
   protected Node(N parent) {
     this.parent = parent;
     parent.children.add( (N)this ); // warning: unchecked cast
   }
   ...
 }

ターゲットタイプがタイプパラメータであるキャストは、実行時に検証できず、チェックされていない警告が発生します。この安全でないキャストは、予期しないClassCastExceptionの可能性をもたらすため、回避するのが最善です。

上記のコードがClassCastExceptionをスローする例を誰かに教えてもらえますか?

ありがとう。

4

1 に答える 1

5

最初のコード サンプル

最初のコード サンプルには、コンパイル エラーがあります。IDEで自分で確認できます。

私は言う:The method add(N) in the type List<N> is not applicable for the arguments (Node<N>)

問題は、N がノードのサブタイプであることです。N のリストは、StupidNode のリストである可能性があります。ここで、StupidNode は Node のサブクラスです。しかし、現在のインスタンスは StupidNode ではない可能性があり、Node の別のサブクラスである可能性があるため、追加が間違っている可能性があります


2 番目のコード サンプル

2 番目のコード サンプルは、開発者が理解できないコンパイル時のエラーに悩まされ、コンパイラが間違っていると信じてキャストを強制しようとするコードです。このようなキャストはコードをコンパイルしますが、実行時に同じ条件で壊れる可能性があります(上で説明したように)。

したがって、コンパイラは警告を発行し、何かが間違っている可能性があることを理解できるようにします。


サンプル問題

前の両方のコード サンプルで、呼び出し元のコードが次のように記述した場合に問題が発生する可能性があります (2 つのサブクラスNodeANodeBNode)。

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);

2 行目で、 のコンストラクターで実行されるコードは次のNodeように解釈されます ( format パラメーターNを現在のパラメーターで置き換えます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
   }
  // ...
 }

ご覧のとおり、呼び出し元の 2 行目はNodeAインスタンスを渡しますが、コンストラクターは!をNode期待しています。NodeBしたがって、エラー...


コメントで要求された更新: サブクラス NodeA (または NodeB) のサンプル コード。

public class NodeA extends Node<NodeA>  {
   public NodeA(NodeA parent) {
     super(parent);
   }
}
于 2009-12-24T13:12:14.730 に答える