java中声明自引用node类必须用类名(如node或node)作为字段类型,不可用object、void或node;next初始值为null而非new node();遍历时需确保current非null才访问data;泛型下data可为null但next是否为null决定结构完整性。

Java中如何声明自引用的Node类
自引用不是语法糖,而是明确写出「当前类类型的字段」。Java不支持self或this作为类型,必须用类名本身——比如Node类里存一个Node类型的next字段。
常见错误是写成Object、Object next,或者误用泛型通配符如Node>,导致后续无法安全调用next.data等成员。
-
next字段必须是Node(或带泛型的Node<t></t>),不能是Object或void - 构造函数里可接受
data和next参数,但next类型必须严格匹配 - 如果加泛型,整个类定义要同步:
class Node<t> { T data; Node<t> next; }</t></t>
为什么next字段必须是Node而非Node>
泛型擦除后,Node<string></string>和Node<integer></integer>都变成原始类型Node,但编译期类型检查仍依赖泛型签名。若声明为Node> next,你就无法安全地写next.data(因为? extends Object不保证有data字段),也无法赋值给Node<string></string>变量。
典型报错:Error: incompatible types: Node> cannot be converted to Node<string></string>
立即学习“Java免费学习笔记(深入)”;
- 用
Node<t></t>保持类型一致性,让next.data可读可写 -
Node>只适合做只读容器(如方法参数),不适合链表节点间的连接 - 如果真要混用不同类型,应靠上层容器(如
List<object></object>)处理,而不是在Node内部妥协
初始化next时null还是new Node()?
链表节点的next初始值必须是null,不是new Node()。后者会无条件创建新节点,造成内存泄漏和逻辑错乱——比如插入第一个元素时就凭空多出一个空节点。
常见错误现象:遍历时突然冒出data=null的节点,或size()比实际多1。
- 构造函数中
next = null是标准做法;next = new Node()是典型反模式 - 只有在明确需要哨兵节点(sentinel node)时才主动创建空节点,且需单独命名(如
headSentinel),不作为普通节点的默认行为 - 使用IDE自动补全时注意别选错模板——有些模板会默认初始化对象,需手动删掉
遍历单向链表时最容易漏掉的边界检查
所有基于while (current != null)的遍历,都要确认current是从有效节点开始的。最常踩的坑是把head设为null后,直接传入循环而不判断,导致NullPointerException发生在第一行current.data。
错误示例:
Node current = head;<br>while (current != null) {<br> System.out.println(current.data);<br> current = current.next; // 这里没问题,但上面那行可能炸</br>}
- 访问
current.data前,必须确保current非null;哪怕循环条件写了!= null,也要注意是否在循环体开头就用了它 - 删除节点时,若删的是
head,记得更新head = head.next,否则残留引用会导致后续遍历跳过首节点 - 泛型类中,
data可能是null(如Node<string></string>),但next字段本身是否为null才是结构关键,别混淆数据空和指针空










