双向链表node类应私有封装data、prev、next三字段,仅提供带校验的getter/setter,指针操作由linkedlist统一管理,确保数据安全、结构一致与访问可控。

用 class 封装双向链表的 Node 节点,核心不是“藏起来”,而是通过私有属性明确边界、控制访问路径,让外部无法绕过逻辑直接篡改指针或数据。真正的“完美封装”体现在:数据不可裸露、指针不可误连、结构一致性由类自身保障。
私有属性必须包含 data、prev、next 三者
双向链表节点的本质是“带前后链接的数据容器”。这三个字段缺一不可,且都应设为私有:
- data:存储业务值,必须私有——防止外部绕过类型校验或业务约束直接赋值
- prev 和 next:指向邻接节点的引用,必须私有——避免外部强行修改指针导致链断裂或环错乱
例如 JavaScript 中可这样定义(TypeScript 更佳):
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
class ListNode<t> {
#data: T;
#prev: ListNode<t> | null = null;
#next: ListNode<t> | null = null;
constructor(data: T) {
this.#data = data;
}
// 仅暴露受控的访问方式
get data(): T { return this.#data; }
set data(value: T) { this.#data = value; } // 可加校验逻辑
get prev(): ListNode<t> | null { return this.#prev; }
set prev(node: ListNode<t> | null) {
if (node !== null && !(node instanceof ListNode)) {
throw new Error('prev must be ListNode or null');
}
this.#prev = node;
}
get next(): ListNode<t> | null { return this.#next; }
set next(node: ListNode<t> | null) {
if (node !== null && !(node instanceof ListNode)) {
throw new Error('next must be ListNode or null');
}
this.#next = node;
}
}</t></t></t></t></t></t></t>
禁止外部直接操作指针,只允许通过链表类统一管理
Node 类本身不提供 linkBefore、unlink 等破坏性方法。这些逻辑应下沉到 LinkedList 类中,由它负责维护指针一致性:
- 插入时,链表类调用
node.next = target和target.prev = node,但这是内部行为,不是 Node 的职责 - 删除时,链表类先重连前后节点,再将待删节点的
prev和next置为null,防止悬空引用 - Node 不知道自己的位置,也不该知道自己是否在链中——这是链表的上下文,不是节点的属性
构造时即固化结构完整性
节点一旦创建,就应处于自洽状态。尤其在带头双向循环链表中,哨兵节点初始化时需自循环:
- 普通节点:默认
prev和next为null,表示孤立状态 - 哨兵节点(如头结点):构造时显式设置
this.#prev = this、this.#next = this,形成最小闭环 - 所有指针赋值必须成对发生——比如设置
node.next = other时,other.prev应同步更新,但这步必须由链表操作统一完成,不能分散在各处
配合链表类实现真正封装效果
Node 的私有性只有在链表类不暴露其内部引用于外部时才有意义:
-
LinkedList的get(index)方法返回的是数据值,不是节点实例;若必须返回节点,也应返回只读代理或深拷贝副本 - 遍历接口(如
forEach)传入的回调函数接收的是data,而非原始Node - 调试时可通过
toString()或inspect()输出结构摘要,但不开放node.#next的直接访问路径










