
在java中实现一个单向链表,通常需要两个核心组件:表示链表节点的 listnode 类和管理链表整体的 llist2 类。为了提高代码的通用性,我们采用泛型来定义这些类,使其能够存储任意类型的数据。
ListNode<E> 类代表链表中的一个节点。它包含两个主要部分:
class ListNode <E> {
private final E val; // 使用final修饰,表示节点值一旦创建不可变
private ListNode <E> next;
public ListNode(E val, ListNode <E> next){
this.val = val;
this.next = next;
}
public E getVal(){
return val;
}
public ListNode <E> getNext(){
return next;
}
public boolean hasNext() {
return next != null;
}
public void updateNext(ListNode <E> node){
this.next = node;
}
}注意事项:
LList2<E> 类负责管理整个链表,它通常包含指向链表头部 (front) 和尾部 (rear) 的指针,以便于高效地执行添加、删除等操作。
class LList2 <E> {
private ListNode <E> front; // 链表头部节点
private ListNode <E> rear; // 链表尾部节点
public LList2(ListNode <E> front, ListNode <E> rear){
this.front = front;
this.rear = rear;
}
// ... 其他方法 ...
}说明:
立即学习“Java免费学习笔记(深入)”;
实现链表的关键在于正确地处理节点之间的链接关系。本节将重点介绍 addFirst、addLast 和 print 方法的实现,并详细解析在使用泛型时可能遇到的类型兼容性错误。
addFirst 方法用于在链表的头部添加一个新元素。其逻辑是创建一个新节点,使其指向当前的 front 节点,然后更新 front 为这个新节点。如果链表原本为空,新节点同时也是 rear 节点。
public void addFirst(E obj){
front = new ListNode<>(obj, front); // 新节点指向原front
if(rear == null){ // 如果链表为空,则新节点也是rear
rear = front;
}
}addLast 方法用于在链表的尾部添加一个新元素。其核心逻辑是创建一个新节点,然后让当前的 rear 节点指向这个新节点,并更新 rear 为新节点。需要注意的是,当链表为空时,新节点既是 front 也是 rear。
public void addLast(E obj){ // 注意:这里参数是E obj,而不是ListNode<E>
ListNode<E> newNode = new ListNode<>(obj, null); // 创建新节点
if(rear != null) {
rear.updateNext(newNode); // 原尾节点指向新节点
} else {
// 链表为空时,新节点既是front也是rear
front = newNode;
}
rear = newNode; // 更新rear为新节点
}类型兼容性错误解析:incompatible types: ListNode<Integer> cannot be converted to Integer
这个错误通常发生在调用 addLast 方法时,传递了错误的参数类型。例如,当 addLast 方法定义为 public void addLast(E obj),而我们尝试这样调用时:
// 假设 LList2<Integer> myList = ...; myList.addLast(new ListNode<Integer>(-2, null)); // 错误!
错误原因:addLast(E obj) 方法明确声明它期望一个 E 类型的参数,其中 E 代表的是链表存储的“值”的类型(例如 Integer)。然而,在上述错误调用中,我们传递了一个 ListNode<Integer> 类型的对象。ListNode<Integer> 是一个节点对象,而不是一个 Integer 值。Java 编译器会检查泛型类型,发现 ListNode<Integer> 无法直接转换为 Integer,因此抛出 incompatible types 错误。
正确调用方式: 我们应该直接传递要添加的“值”本身,由 addLast 方法内部负责将这个值封装成一个 ListNode 对象。
// 假设 LList2<Integer> myList = ...; myList.addLast(-2); // 正确!直接传递Integer值
代码示例:
public class SingleLinkedListWorkSheetQ2Q3 {
public static void main(String[] args) {
// 构建初始链表:3 -> 2 -> 1 -> 0
ListNode<Integer> rearNode = new ListNode<>(0, null);
ListNode<Integer> listHead = new ListNode<>(1, rearNode);
listHead = new ListNode<>(2, listHead);
listHead = new ListNode<>(3, listHead);
LList2<Integer> myList = new LList2<>(listHead, rearNode);
System.out.print("原始链表: ");
myList.printWhile(); // 第一次打印
myList.addLast(-2); // 正确调用 addLast 方法,添加值-2
System.out.print("添加-2后链表: ");
myList.printWhile(); // 第二次打印,预期输出 [3, 2, 1, 0, -2]
}
}遍历链表是常见的操作,但需要注意不要在遍历过程中意外修改链表的 front 或 rear 指针。
不推荐的遍历方式(会修改 front): 直接操作 front 指
以上就是Java泛型单向链表实现:类型兼容性与最佳实践解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号