面试题答案
一键面试使用泛型实现链表节点类以存储不同类型数据
在Java中,通过在类定义时声明泛型类型参数,可以让链表节点类存储不同类型的数据。以下是一个简单的链表节点类示例:
class ListNode<T> {
T data;
ListNode<T> next;
public ListNode(T data) {
this.data = data;
this.next = null;
}
}
这里<T>
是泛型类型参数,它可以代表任何类型。在创建ListNode
实例时,指定具体的类型,例如ListNode<Integer>
表示该节点存储Integer
类型数据,ListNode<String>
表示存储String
类型数据。
泛型类型擦除机制对链表操作的影响
- 运行时类型信息缺失:Java泛型是通过类型擦除实现的,在运行时,泛型类型参数会被擦除,替换为其限定类型(通常是
Object
,除非有上限类型声明)。这意味着在链表操作中,无法在运行时获取确切的泛型类型信息。例如,在链表的遍历方法中,无法通过instanceof
判断节点存储数据的具体类型。
class LinkedList<T> {
ListNode<T> head;
// 遍历链表方法
public void traverse() {
ListNode<T> current = head;
while (current != null) {
// 无法在运行时判断current.data的具体类型,因为类型已被擦除
current = current.next;
}
}
}
- 类型转换问题:由于类型擦除,从链表节点获取数据时,需要进行显式类型转换。如果类型转换不正确,会抛出
ClassCastException
。例如:
LinkedList<Integer> intList = new LinkedList<>();
intList.head = new ListNode<>(10);
// 获取数据时需要进行类型转换
Integer value = (Integer) intList.head.data;
- 不能创建泛型数组:由于类型擦除,不能直接创建泛型类型的数组。例如
T[] array = new T[10];
是不允许的。在链表实现中,如果需要使用数组来辅助操作(如实现循环链表等更复杂结构),就需要使用Object
数组代替,并在使用时进行类型转换。 - 桥接方法:在泛型类的继承和多态场景下,为了保持兼容性,编译器会生成桥接方法。例如,当子类重写父类的泛型方法时,编译器会生成桥接方法来确保在运行时类型擦除后方法调用的正确性,但这增加了编译和运行时的复杂性。