实现方法中运行时类型检查的Java问题
我正在设计一些java对象来表示图形和树。对于我的用例,我将使用这两种数据类型,但我也希望我的图形算法在我的树上工作实现方法中运行时类型检查的Java问题,java,oop,design-patterns,Java,Oop,Design Patterns,我正在设计一些java对象来表示图形和树。对于我的用例,我将使用这两种数据类型,但我也希望我的图形算法在我的树上工作 import java.util.List; public interface Node<T> { T getValue(); List<? extends Node<T>> getNeighbors(); void addNodes(List<? extends Node<T>> nodes)
import java.util.List;
public interface Node<T> {
T getValue();
List<? extends Node<T>> getNeighbors();
void addNodes(List<? extends Node<T>> nodes);
}
public interface TreeNode<T> extends Node<T> {
List<? extends TreeNode<T>> getChildren();
void addChildren(List<? extends TreeNode<T>> treeNodes);
@Override
default List<? extends Node<T>> getNeighbors() {
return getChildren();
}
@Override
default void addNodes(List<? extends Node<T>> nodes) {
if(nodes.getClass().isInstance(getChildren().getClass())) {
addChildren((List<? extends TreeNode<T>>) nodes);
} else {
throw new RuntimeException("Type error!");
}
}
}
import java.util.List;
公共接口节点{
T getValue();
列表在我看来,Node
是一些数据的容器。Tree
和Graph
是维护节点之间关系的两种方法。因此,可能应该定义三个类:
import java.util.List;
public class Node<T> {
private T value;
public Node(T value) { this.value = value; }
T getValue() { return value; }
}
public abstract class Tree<T> {
private Node<T> root;
public abstract List<? extends Node<T>> getChildren();
public abstract void addChildren(List<? extends Node<T>> nodes);
public Tree(Node<T> root) { this.root = root; }
}
public abstract class Graph<T> {
private Node<T> root;
public abstract List<? extends Node<T>> getNeighbors();
public abstract void addNeighbors(List<? extends Node<T>> nodes);
public Graph(Node<T> root) { this.root = root; }
}
import java.util.List;
公共类节点{
私人T值;
公共节点(T值){this.value=value;}
T getValue(){返回值;}
}
公共抽象类树{
私有节点根;
公共抽象列表如果我理解正确,您想要的是(一个变体)所谓的。节点
类型不仅需要通过其有效负载类型(T)参数化,还需要通过它可以使用的节点类型参数化。因此,您想要:
public interface Node<T, N extends Node<T, N>> {
T getValue();
List<N> getNeighbors();
void addNodes(List<N> nodes);
}
public interface TreeNode<T> extends Node<T, TreeNode<T>> {
List<TreeNode<T>> getChildren();
void addChildren(List<TreeNode<T>> treeNodes);
@Override
default List<TreeNode<T>> getNeighbors() {
return getChildren();
}
@Override
default void addNodes(List<TreeNode<T>> nodes) {
addChildren(nodes);
}
}
公共接口节点{
T getValue();
列出getneights();
void addNodes(列表节点);
}
公共接口树节点扩展节点{
列出getChildren();
void addChildren(列出树节点);
@凌驾
默认列表getNeights(){
返回getChildren();
}
@凌驾
默认的void addNodes(列表节点){
添加子节点(节点);
}
}
演示(仅显示编译):我不理解代码中节点
和树节点
之间的区别。在我看来,节点
是一些数据的容器。树
和图
是维护节点之间关系的两种方法。因此,也许应该定义三个类来表示这一点design@AdamSiemion节点是一个图节点,TreeNode是一棵树node@SharonBenAsher请您详细说明一下好吗?nodes.getClass()
您现有的它永远不会工作,因为getClass()
始终返回运行时类型,该类型将删除实际参数化类型。因此,无论节点的子类型如何,类都将进行相同的比较。如果要检查列表中值的类型,则需要为元素类型获取类
对象,例如类
;没有此类由于擦除,将其作为类进行处理。这种方法的问题是:如果我为Graph类编写BFS,我就不能在tree类上使用它。那么tree和Graph之间的真正区别是什么?这只是语义吗?当有人使用TreeNode时,假设该节点满足tree属性。即树中没有圆。当有人使用一个常规节点,假设没有一种方法可以完成相同的事情而不需要人们指定N?不幸的是,没有。但是如果客户端代码直接与具体的子类型一起工作,比如TreeNode
,那么就不需要显式地命名N的类型。是否可以编写代码它直接在这个节点接口上运行?我认为这是不可能的。我想要捕获的一个用例是为节点编写代码并在TreeNode中重用它,您只需要为N使用通配符类型。类似于Node
的东西将允许您调用getValue()
以类型安全的方式。您将无法向其中添加节点,但这是正确的,因为如果您只有一个节点
,那么您就不知道要添加哪些节点作为其子节点。
public interface Node<T, N extends Node<T, N>> {
T getValue();
List<N> getNeighbors();
void addNodes(List<N> nodes);
}
public interface TreeNode<T> extends Node<T, TreeNode<T>> {
List<TreeNode<T>> getChildren();
void addChildren(List<TreeNode<T>> treeNodes);
@Override
default List<TreeNode<T>> getNeighbors() {
return getChildren();
}
@Override
default void addNodes(List<TreeNode<T>> nodes) {
addChildren(nodes);
}
}