【发布时间】:2019-03-17 11:08:04
【问题描述】:
我需要一个可以在不同节点实现上工作的双向链表。请注意,我不想要包含通用数据的节点,例如 DoublyLinkedNode<T>,而是像 DoublyLinkedList<N extends DoublyLinkedNode<T>> 这样的节点。
确切地说,我在一般情况下使用带有标准节点的列表,但在我程序的其他部分,我需要带有附加字段的节点。所以我将通用节点实现为
public class DoublyLinkedNode<T> {
DoublyLinkedNode<T> before, after;
T value;
}
特殊类型为
public class DoublyLinkedSpecialNode<T, S> extends DoublyLinkedNode<T> {
S specialValue;
}
现在,在我的 DoublyLinkedList 实现中,我希望能够同时处理这两种情况,因为所有代码基本上都在摆弄两个实现显然共有的指针。
这给出了一些要求:
1) 当我使用特殊节点时,我希望能够将其作为DoublyLinkedSpecialNode 类型返回,以便能够访问其他字段。
2) 列表必须使用 DoublyLinkedNode 类型来访问节点的指针。
3) 列表将指向的节点分配给其他节点,例如head = node.after;,所以特殊节点中的指针类型必须与列表中的类型相同。
扩展列表没有意义,因为那时我无法更改方法的返回类型。因此我尝试了两个想法但没有成功:
已经提到的解决方案:从 DLN 扩展的通用节点类型
列表如下所示:
public class DoublyLinkedList<T, N extends DoublyLinkedNode<T>> {
N head, tail;
N tail() {
return tail; // OK
}
void remove(N node) {
if (head == node) {
head = node.after; // Type error
}
...
此解决方案与要求 3 冲突),因为在列表中类型是从 DLN 扩展的 N,但在节点实现 N 中,指针是基类/接口 DLN 的类型(指针类型理论上可以比 N 更一般)。
基础 DLN 而非泛型
在这种情况下,列表在基类节点上工作,并且由于多态性而接受子类:
public class DoublyLinkedList<T> {
DoublyLinkedNode<T> head, tail;
DoublyLinkedNode<T> tail() {
return tail;
}
void remove(DoublyLinkedNode<T> node) {
if (head == node) {
head = node.after; // OK
}
...
但是tail()只能返回一般类型的节点,与1)冲突。我宁愿不使用强制转换,因为我认为这是不好的做法(?),但也因为实现对性能至关重要。肯定有更好的方法吗?
【问题讨论】: