我需要一个可以在不同的节点实现上工作的双向链表。请注意,我不希望包含通用数据的节点,例如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)冲突。我宁愿不使用强制转换,因为我认为这是不好的做法(?),而且因为实现对性能至关重要。当然有更好的方法吗?
答案 0 :(得分:0)
我发现了另一个不错的解决方案,虽然性能不高,但比上一个解决方案更优雅。
该思想仅使用一种类型的节点,并将各种内容包装在通用容器中。 DLN代码如下:
public class DoublyLinkedNode<C> {
DoublyLinkedNode<C> before, after;
C content;
public static class ValueContent<T> {
T value;
}
public static class ValueSpecialContent<T, S> extends ValueContent<T> {
S specialValue;
}
}
列表实现如下所示:
public class DoublyLinkedList<C> {
DoublyLinkedNode<C> head, tail;
public DoublyLinkedNode<C> head() {
return head;
}
void remove(DoublyLinkedNode<C> node) {
if (head == node) {
head = node.after;
...
我可以从调用类中访问特殊字段,如下所示:
DoublyLinkedList<SpecialContent<SpecialType>> list;
SpecialType s = list.head().content.specialValue;
存在一些开销,因为每个节点都必须实例化该容器类,但是我认为它仍然比强制转换更好。我必须检查性能影响。