在我的通用Tree实现中泛型和子类型的问题

时间:2011-03-31 18:34:29

标签: java generics inheritance tree covariance

考虑以下代码:

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 个答案:

答案 0 :(得分:2)

您想使用所谓的getThis() trick。声明一个像这样的新方法:

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

然后,当您需要使用this时,只需拨打getThis()即可。作为旁注,在@Michael Williamson的回答中实现这种方法会使像BadNode这样的类混淆,从而使得首先编写这样一个类更难(这是一件好事)。

答案 1 :(得分:1)

不保证类型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&lt; GoodNode,Integer&gt;,返回类型getRoot()是GoodNode。由于BadNode无法强制转换为GoodNode,因此存在类强制转换异常:

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

答案 2 :(得分:1)

也许你想要“过于通用”?

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(); // <--- ???
        }
    }
...
}

BTW:您可能想要调用parent.getRoot()而不是getParent()的内容。

答案 3 :(得分:1)

为什么在extends子句中使用原始类型?这可能会阻碍类型推断。 请尝试以下方法:

public class TreeNode<T extends TreeNode<T,E>, E> {