互补通用 类

complementary generic classes

我有两个摘要类: 容器、节点

一种Container永远包含同一种Node,一种Node只属于它对应的容器: NodeTypeA存放在ContainerTypeA中,没有其他Node的子类存放在里面。 NodeTypeB存放在ContainerTypeB中,没有其他Node的子类存放在里面。从节点到其容器的反向引用也应该知道容器的类型,因此关系是双向的。

我在 Java 中实现这个有问题。

我是这样做的:

Container<C extends Container<C,N>, N extends Node<C,N>>
Node<C extends Container<C,N>, N extends Node<C,N>>

但是,当我在 Container 中定义以下字段时,出现错误:

private List<N> nodes;

错误消息说我应该用 Node 替换 N。这对我来说似乎是多余的。为什么会发生这种情况,我怎样才能让程序理解这一点

N

应该等于

Node<C,N>

测试用例:

https://ideone.com/wam0gi

这背后的目的:

有许多不同类型的节点和许多不同类型的交互方式。但是,它们有一些共同的主题。 Container和Node应该是抽象的类在其中我可以定义方法和抽象方法来定义这些共同的主题。 ContainerA 和 NodeA 将一起定义一种特定的交互方法。我为此使用泛型,因为如果我的 IDE 足够聪明,知道 ContainerA 中的任何节点始终是 NodeA,并且 NodeA 的所有者始终是 ContainerA,那么我可以避免一些不必要的类型转换。

(注:本题类似但不等于Complementary generic types)

除了一些微不足道的错误(abstract 应该在 java 中的 class 之前,第 16 行 Node 的构造函数中错误的类型变量 L,试图在第 18 行访问私有字段),你的语义问题在第 18 行。this 的类型是 Node<C,N>,而不是 N

实现你的目标的一种方法是在Node中添加一个抽象方法,其中returnsN,所有子类将通过返回this来实现它。

abstract protected N me();

然后,将 setter 添加到 Container 后,您需要将第 18 行更改为

owner.add( me() );

How can I get the program to understand that N should be equal to Node<C,N>

他们不平等。 N 延长 Node<C, N>

private List<N> nodes;

表示 Node<C, N>.

的某个子类的列表

您将很难添加到这样的列表。

考虑

List<N> nodes = ...;

Node<C, N> node = new Node<>(...);
nodes.add(node);  // ERROR because node might not be the right subclass

List<Node<C, N>> nodes = ...;

Node<C, N> node = new Node<>(...);
nodes.add(node);  // OK.

List<N> nodes = ...;
N node = new Node<C, N>(...);   // ERROR.  Not all Node<C, N> are N
// N is a sub-type not a super-type of Node<C, N>
nodes.add(node);

如果 Node 是最终的,而你说它不是,"""

There are many different kinds of Nodes

""", 那么你可以

N node = (N) new Node<C, N>(..);  // Unchecked conversion

但是这种类型擦除规则的弯曲是不必要的,即使它在您的程序上下文中是安全的。