我希望“children”字段包含具有包含对象类型的对象列表。但是,当继承时,我会因为向下转换而出错。我可以使用什么策略来保持层次结构,同时又能够适本地访问子对象?
public class Node<T>{
protected T value;
protected Node<T> parent;
private ArrayList<Node<T>> children;
public Node(T value){
this.value = value;
this.children = new ArrayList<Node<T>>();
}
public ArrayList<Node<T>> getChildren(){
return this.children;
}
//...other methods...//
}
当我尝试在此类中调用 getChildren() 时,出现“类型不匹配”错误,因为它正在尝试向下转型。
public class DecidableTree<T extends Decidable<T>> extends Node<T>{
public DecidableTree(T value) {
super(value);
}
public randomInvolvedFunction(){
//...other code...//
for(DecidableTree<T> child : this.getChildren()){
child.decidableTreeSpecificMethod();
}
//...other code...//
}
//...other methods...//
}
不幸的是,我不能只覆盖 getChildren() 函数,因为返回类型必须匹配。
最佳答案
问题
您遇到的问题是您确实在向下转型,您试图将 Node
的任何给定实例视为 DecidableTree
。虽然您当然可以将 DecidableTree
的任何实例视为 Node
,因为它继承自 Node
,但这对另一个实例不起作用一路走来。
解决方案
糟糕的方式
您当然可以使用 instanceOf
运算符直接检查实例类型是否正确,但有一种更简洁的方法可以做到这一点。
清洁方式
您可以通过用两个通用值对 Node
类进行参数化来做到这一点。一个 V
代表给定 Node
的值,另一个 T
代表 Node< 的实际具体实例
.
例如,
public abstract class Node<T, V> {
protected V value;
protected Node<T,V> parent;
private List<T> children;
public Node(V value){
this.value = value;
this.children = new ArrayList<T>();
}
public List<T> getChildren(){
return this.children;
}
public void addChild(T child){
this.children.add(child);
}
public V getVal(){
return this.value;
}
}
拆解
通过用额外的类型变量T
参数化Node
,这允许我们返回父类中给定具体类型的值,而无需真正知道那是什么具体类型将是。如果这仍然令人困惑,考虑我们的新实例 DecidableTree
可能会帮助您理解发生了什么,
public class DecidableTree<V> extends Node<DecidableTree<V>, V> {
public DecidableTree(V value) {
super(value);
}
public void randomInvolvedFunction(){
for(DecidableTree<V> child : this.getChildren()){
System.out.println(child.getVal());
}
}
}
DecidableTree
在实际值类型方面仍然是通用的,但在 T
方面不是通用的。它说 T
是它自己的一个实例。这使我们能够在不向下转型的情况下从父级中获取值。
这将编译并正常工作,现在您可以直接根据泛型描述所有类型。请注意,我添加了一些方法,以便您可以进行一些有意义的测试。
最后一点
在您的示例中,我还将 Node
更改为抽象的,将 ArrayList
更改为 List
,除了它被实例化的那一行。我假设您永远不会直接创建 Node
的实例,因此它应该是 abstract
。至于 ArrayList
,最佳做法是通过接口(interface)引用数据结构,在本例中为 List
,而不是通过实际实现(除非有一些非常具体的原因不这样做)。这使您将来可以非常轻松地更改数据结构,只需更改一行代码即可。
关于java - Java中如何处理自引用和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25815183/