cod*_*dle 4 java generics inheritance
我希望字段"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...//
}
Run Code Online (Sandbox Code Playgroud)
当我尝试在这个类中调用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...//
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我不能只重写getChildren()函数,因为返回类型必须匹配.
iso*_*cte 11
你遇到的问题是你确实是在倾向,你试图将任何给定的实例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;
}
}
Run Code Online (Sandbox Code Playgroud)
通过Node额外类型变量的参数化T,这允许我们返回父类中给定具体类型的值,而不实际知道具体类型是什么.如果这仍然令人困惑,考虑到我们的新实例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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
DecidableTree关于实际值类型仍然是通用的,但它不是通用的T.它说a T是它自己的一个实例.这允许我们从父节点获取值而无需向下转换.
这将编译并正常工作,现在您可以直接根据泛型描述所有类型.注意我添加了一些方法,以便您可以进行一些有意义的测试.
在你的榜样,我也随之变化Node是抽象的,ArrayList是List无处不在,除了在其上实例化的路线.我假设你永远不会直接创建实例Node,所以它应该是abstract.至于ArrayList,这是最好的做法是指你的数据结构,通过该接口,在这种情况下List,而不是由实际执行(除非有一些非常具体的理由不).这使您可以通过仅更改一行代码来非常轻松地更改数据结构.