gpt4 book ai didi

java - 泛型树,自界泛型

转载 作者:搜寻专家 更新时间:2023-11-01 03:14:15 24 4
gpt4 key购买 nike

我要为我的一个项目添加通用性。我喜欢泛型,因为它使我的代码更健壮、 self 记录并消除了所有那些丑陋的转换。

但是,我遇到了一个棘手的案例,并且在尝试为我的一个结构表达“递归”约束时遇到了一些问题。

这基本上是某种“通用”树,带有双链接(到子节点和父节点)。我最大限度地简化了类(class)以显示问题:

public class GenericTree<
ParentClass extends GenericTree<?, ?>,
ChildClass extends GenericTree<?, ?>>
{
// Attributes
private ArrayList<ChildClass> children = new ArrayList<ChildClass>();
private ParentClass parent = null;

// Methods
public void setParent(ParentClass parent) {
this.parent = parent;
}

public void addChild(ChildClass child) {
child.setParent(this);
this.children.add(child);
}
}

问题出在指令上:child.setParent(this)

Java 给出以下错误:

Bound mismatch: The method setParent(?) of type ChildClass is not applicable for the
arguments (GenericTree). The wildcard parameter ? has no lower bound, and may actually be more restrictive than argument GenericTree

我想要的是能够表达类似的东西:

public class GenericTree<
ParentClass extends GenericTree<?, ?>,
ChildClass extends GenericTree<[THIS_VERY_CLASS], ?>>

要说子类的父类应该是自己...

我看过一些关于自绑定(bind)泛型的文章,但我不知道如何在这种情况下应用它。

如有任何帮助,我们将不胜感激。

最佳答案

不要对非均匀树使用泛型,使用接口(interface)和强制转换。

虽然您可以使用泛型解决一些问题,但生成的代码会很脆弱,向您显示您以前从未见过的错误消息,修复错误通常会导致 try&error,即使您可以编译它,您不知道为什么 ;-)

[EDIT2] 添加了 addChild() 和下面的用法示例。

[编辑] 还在我身边吗?如果确实需要,请使用此 API:

interface ParentNode<Child> {
List<Child> getChildren();
void addChild(Child child);
}
interface ChildNode<Parent> {
void setParent(Parent parent);
Parent getParent();
}
// There is no way to avoid this because we would need to define
// "Node" recursively.
@SuppressWarnings( "rawtypes" )
class Node<
Parent extends ParentNode<? extends Node>,
Child extends ChildNode<? extends Node>
>
implements
ParentNode<Child>,
ChildNode<Parent>
{
private Parent parent;
public Parent getParent() { return parent; }
public void setParent(Parent parent) {
this.parent = parent;
// Here, we must case the child to a type that will accept Node
@SuppressWarnings( "unchecked" )
ParentNode<Node> cast = (ParentNode)parent;
cast.addChild(this); // Note: Either add the child here ...
}

private List<Child> children;
public List<Child> getChildren() { return children; }
public void addChild( Child child ) {
children.add(child);
// Here, we must case the child to a type that will accept Node
@SuppressWarnings( "unchecked" )
ChildNode<Node> cast = (ChildNode)child;
cast.setParent(this); // ... or here but not twice :-)
}
}

即将这两个功能(向上看和向下看)拆分为两个接口(interface),然后创建一个实现这两个接口(interface)的节点类型。这允许您将叶节点和根节点定义为特殊节点(没有两个 API 之一),或者您可以像定义任何其他节点一样定义它们并在“不受支持”的方法中返回 null

用法:

public class DirFileNode extends Node<DirFileNode, DirFileNode> {
}
public class TreeUsage {
public static void main( String[] args ) {
DirFileNode node = new DirFileNode();
DirFileNode node2 = new DirFileNode();
node.addChild( node2 );
// Why yes, I do love infinite loops. How can you tell?
node2.addChild( node );
}
}

您可以看到,API 确保所有内容都是类型安全的,但在内部,您必须强制转换。只要您不在节点中使用泛型类型,这就很简单。如果这样做,声明会变得一团糟。

关于java - 泛型树,自界泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3333590/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com