我有两个抽象类: 容器,节点
一种Container将始终包含相同类型的Node,并且一种节点将仅属于其对应的容器: NodeTypeA存储在ContainerTypeA中,并且其中没有其他Node子类存储在其中。 NodeTypeB存储在ContainerTypeB中,并且其中没有其他Node子类存储在其中。从Node到其Container的反向引用也应该知道Container的类型,因此关系是双向的。
我在使用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>
测试用例:
背后的目的:
有许多不同类型的节点和许多不同类型的节点可以互动。但是,他们有一些共同的主题。 Container和Node应该是抽象类,我可以在其中定义方法和抽象方法来定义这些常见主题。然后,ContainerA和NodeA将定义一种特定的交互方法。我使用泛型是因为如果我的IDE足够智能以便知道ContainerA中的任何Node总是NodeA,并且NodeA的所有者总是ContainerA,那么编程变得容易得多,所以我可以避免一些不必要的类型转换
(注意:这个问题类似但不等于Complementary generic types)
答案 0 :(得分:1)
除了几个微不足道的错误(abstract
应该在java class
之前,错误的类型变量L
在第16行的Node
的构造函数中,尝试访问私有字段在第18行,你的语义问题在第18行。this
的类型是Node<C,N>
,而不是N
。
实现目标的一种方法是向Node
添加一个返回N
的抽象方法,所有子类将通过返回this
来实现它。
abstract protected N me();
然后,一旦您为Container
添加了适当的设置器,您就会将第18行更改为
owner.add( me() );
答案 1 :(得分:1)
如何让程序理解这一点
N
应该等于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
VS
List<Node<C, N>> nodes = ...;
Node<C, N> node = new Node<>(...);
nodes.add(node); // OK.
VS
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
是最终的,你说它不是,&#34;&#34;&#34;
有许多不同类型的节点
&#34;&#34;&#34;,然后你可以做
N node = (N) new Node<C, N>(..); // Unchecked conversion
但即使在程序的上下文中它是安全的,这种类型擦除规则的修改也是不必要的。