我想使用由特定于域的节点DomainTree组成的特定于域的树DomainNode,但是将所有通用函数保留在模板类TreeNode中。首先,我从模板Tree<T>Node<T>开始(其中T是节点数据的类型)。然后DomainTree使用Node<T>接口,这不是我想要的。它应该在DomainNode对象上起作用。

为了解决这个问题,我将通用树的模板参数更改为Tree<N extends Node<?>>(下面的实现)。现在,我可以通过将树实例化为DomainNode来使用DomainTree<DomainNode>

尽管如此,我仍然在(1)处遇到编译错误,因为getChildren()返回了Node<T>的列表,尽管我确定N,但它似乎无法转换为N extends Node<?>的列表。

为什么这不起作用?如何设计它,以便DomainTree可以与DomainNode一起使用?

通用树

import java.util.ArrayList;
import java.util.List;

class Tree<N extends Node<?>> {

    public N rootElement;

    public List<N> toList() {
        List<N> list = new ArrayList<N>();
        walk(rootElement, list);
        return list;
    }

    private void walk(N element, List<N> list) {
        list.add(element);
        List<N> children = element.getChildren(); // (1) Cannot convert from List<Node<T>> to List<T>
        for (N data : children) {
            walk(data, list);
        }
    }
}

class Node<T> {

    public T data;
    public List<Node<T>> children;

    public List<Node<T>> getChildren() {
        if (this.children == null) {
            return new ArrayList<Node<T>>();
        }
        return this.children;
    }

    public void addChild(Node<T> child) {
        if (children == null) {
            children = new ArrayList<Node<T>>();
        }
        children.add(child);
    }
}


问题特定树

class DomainTree extends Tree<DomainNode> {

    public void build() {
            for (DomainNode node : toList()) {
                // process...
            }
        }
}

class DomainNode extends Node<String> {

}

最佳答案

就目前的代码而言,问题是对于给定的Node<T>,编译器无法知道从List返回的toList()的类型与类本身是相同的Node<T>

您需要的是一种自引用泛型类型:

class Node<T, N extends Node<T, N>> {

    public T data;
    public List<N> children;

    public List<N> getChildren() {
        return children == null ? Collections.<N>emptyList() : children;
    }

    public void addChild(N child) {
        if (children == null) {
            children = new ArrayList<N>();
        }
        children.add(child);
    }
}


现在,从toList()返回的类型与该类型本身相同。

然后DomainNode变为:

class DomainNode extends Node<String, DomainNode> {
    //
}


Tree的签名略有变化,变为:

class Tree<N extends Node<?, N>> {


现在,您的用法示例可以编译:

class DomainTree extends Tree<DomainNode> {
    public void build() {
        for (DomainNode node : toList()) {
            // process...
        }
    }
}




我还增加了其他一些效率。

10-07 17:16