Проблема с Обобщением и подтипом в моей общей реализации Tree - PullRequest
2 голосов
/ 31 марта 2011

Рассмотрим этот код:

public class TreeNode<T extends TreeNode<T, E>, E> {
    protected T parent;
    protected E data;
    protected List<T> children = new ArrayList<T>();

    public TreeNode(T parent, E data) {
        this.parent = parent;
        this.data = data;
    }

    public T getRoot() {
        if (parent == null) {
            return this;       //<---- Problem is here!
        } else {
            return getParent().getRoot();

        }
    }

    public T getParent() {
        if (parent == null) {
           throw new RuntimeException("This already the parent!");
        } else {
            return parent;
        }
    }
}

/*
  incompatible types
    required: T
    found:    TreeNode<T,E>
*/

Как я могу это исправить и заставить мой код работать?

Ответы [ 4 ]

2 голосов
/ 02 апреля 2011

Вы хотите использовать так называемый трюк getThis () .Объявите новый метод следующим образом:

/** Subclasses must implement this method as {@code return this;} */
protected abstract T getThis();

Затем, когда вам нужно будет использовать this, просто вызовите getThis().В качестве примечания, реализация этого метода приведет к путанице с классом, подобным BadNode в ответе @Michael Williamson, что затруднит написание такого класса в первую очередь (что хорошо).

1 голос
/ 31 марта 2011

Может быть, вы пытаетесь быть "слишком общим"?

public class TreeNode<E> {
    protected TreeNode<E> parent;
    protected E data;
    protected List<TreeNode<E>> children = new ArrayList<TreeNode<E>>();

    public TreeNode(T parent, E data) {
        this.parent = parent;
        this.data = data;
    }

    public TreeNode<E> getRoot() {
        if (parent == null) {
            return this;       
        } else {
            return getParent(); // <--- ???
        }
    }
...
}

Кстати: вы можете захотеть вызвать что-то вроде parent.getRoot () вместо getParent ().

1 голос
/ 01 апреля 2011

Почему вы используете необработанный тип в предложении extends? Это может помешать выводу типа. Попробуйте следующее:

public class TreeNode<T extends TreeNode<T,E>, E> {
1 голос
/ 31 марта 2011

Не гарантируется, что тип T совпадает с типом самого класса, поэтому вам нужно добавить приведение к строке, которая не компилируется:

public T getRoot() {
    if (parent == null) {
        return (T)this;
    } else {
        return getParent();
    }
}

Чтобы привести простой пример кода, который будет содержать ошибку ввода:

public class GoodNode extends TreeNode<GoodNode, Integer> {
    public GoodNode(GoodNode parent, Integer data) {
        super(parent, data);
    }
}

public class BadNode extends TreeNode<GoodNode, Integer> {
    public BadNode(GoodNode parent, Integer data) {
        super(parent, data);
    }

    public static void main(String[] args) {
        GoodNode node = new BadNode(null, null).getRoot();
    }
}

Запуск BadNode.main вызывает ошибку при печати, поскольку BadNode (null, null) .getRoot () возвращает объект класса BadNode (так как у него нет родителя), но поскольку BadNode расширяет TreeNode , тип возврата getRoot () - это GoodNode. Поскольку BadNode не может быть приведен к GoodNode, есть исключение приведения класса:

Exception in thread "main" java.lang.ClassCastException: BadNode cannot be cast to GoodNode
    at BadNode.main(BadNode.java:7)
...