我想使用由特定于域的节点DomainTree
组成的特定于域的树DomainNode
,但是将所有通用函数保留在模板类Tree
和Node
中。首先,我从模板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...
}
}
}
我还增加了其他一些效率。