Первый пример кода
В первом примере кода есть ошибка компиляции. Вы можете проверить это самостоятельно в своей 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, поэтому добавление может быть неправильным .
Второй пример кода
Теперь во втором примере кода разработчик, раздраженный ошибкой во время компиляции, которую он не понимает, считает, что компилятор ошибочен, и пытается вызвать приведение.
Такое приведение приводит к компиляции кода, но может сломаться во время выполнения в тех же условиях (как объяснено выше).
Поэтому компилятор выдает предупреждение, чтобы помочь вам понять, что что-то может быть не так.
Пример задачи
Для обоих предыдущих примеров кода проблема может возникнуть, если код вызывающего кода записывается (для двух подклассов 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
! Отсюда и ошибка ...
ОБНОВЛЕНИЕ согласно запросу: пример кода для подклассов NodeA (или NodeB).
public class NodeA extends Node<NodeA> {
public NodeA(NodeA parent) {
super(parent);
}
}