Дженерики Java объяснение приема GetThis

Я читаю о Дженериках Java, и я столкнулся с этой темой, где я немного смущен.

От: http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205

public abstract class Node >  {
   private final List children = new ArrayList();
   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 getChildren() {
     return children;
   }
 }

public class SpecialNode extends Node {
   public SpecialNode(SpecialNode parent) {
     super(parent);
   }
} 

Прокрутка ниже несколько экранов...

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

Броски, целевой тип которых является параметром типа, не могут быть проверены во времени выполнения и выводе к предупреждению непроверенному. Этот небезопасный бросок представляет потенциал для неожиданного ClassCastException s и лучше всего избегается.

Кто-то мог дать мне пример, где вышеупомянутый код бросает ClassCastException?

Спасибо.

7
задан javaStudent 24 December 2009 в 12:31
поделиться

1 ответ

Первый пример кода

В первом примере кода присутствует компиляция-ошибка. Вы можете проверить его самостоятельно в своей IDE.

Мой говорит : Метод add(N) в типе List неприменим для аргументов (Node)

Проблема в том, что N является подтипом Node. Список N может быть списком StupidNode, где StupidNode является подклассом Node. Но текущий экземпляр может и не быть StupidNode, это может быть другой подкласс Node, поэтому добавление может быть неправильным.


Второй пример кода

Теперь второй пример кода - тот, где разработчик, раздосадованный ошибкой времени компиляции, которую он не понимает, считает, что компилятор ошибается и пытается форсировать кастинг. Такой слепок заставляет код компилироваться, но может сломаться во время выполнения в тех же условиях (как объяснено выше).

Следовательно, компилятор выдает предупреждение, чтобы помочь понять, что что-то может быть не так.


Пример проблемы

Для обоих предыдущих примеров кода проблема может возникнуть, если вызывающий код пишет (для двух подклассов NodeA и NodeB из Node):

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

Во второй строке код, который будет запущен в конструкторе Node, будет интерпретироваться подобно (заменив параметр форматирования 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
   }
  // ...
 }

Как видно, вторая строка вызывающего абонента будет передавать экземпляр NodeA, в то время как конструктор Node ожидает NodeB! Отсюда и ошибка...


UPDATE, о которой просит комментарий : пример кода для подклассов NodeA (или NodeB).

public class NodeA extends Node<NodeA>  {
   public NodeA(NodeA parent) {
     super(parent);
   }
}
5
ответ дан 7 December 2019 в 12:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: