泛型
在聊泛型之前,我们得知道什么是泛型。泛型是一种把类型明确的工作推迟到创建对象或调用方法的方式,即将类型当作参数进行传递。
注意,泛型必须是引用类型!
那么我们为什么要使用泛型呢?接下来举个例子,假设我们自己写一个简单的 LinkedList 链表。
示例
public class MyLinkedList {
private int size;
private int element;
Node head;
Node last;
public void add(int element) {
Node n = new Node(element, null, null);
if(head == null) { //无节点时
n.prev = null;
n.next = null;
head = n;
last = n;
}
else { //有节点时
last.next = n;
n.prev = last;
last = n;
}
size++;
}
class Node {
int element;
Node prev;
Node next;
public Node(int element, Node prev, Node next) {
this.element = element;
this.prev = prev;
this.next = next;
}
}
}
这样我们就完成了一个简单可以实现 add 方法的 LinkedList 链表。但是我们可以看到,这个链表只能存储 int 类型的数据。那如果我们要增加其他类型的数据怎么办呢?再写一个其他类型的 LinkedList 吗?这显然是不可能的。因此这时候,我们就需要用到泛型了。我们给上面的代码加入泛型。
示例
public class MyLinkedList<T> {
private int size;
private T element;
Node head;
Node last;
public void add(T element) {
Node n = new Node(element, null, null);
if(head == null) { //无节点时
n.prev = null;
n.next = null;
head = n;
last = n;
}
else { //有节点时
last.next = n;
n.prev = last;
last = n;
}
size++;
}
class Node<T> {
T element;
Node prev;
Node next;
public Node(T element, Node prev, Node next) {
this.element = element;
this.prev = prev;
this.next = next;
}
}
}
这样我们就可以将类型当成参数传入其中,如
public class Test {
public static void main(String[] args) {
MyLinkedList<String> t1 = new MyLinkedList<>();
t1.add("a");
t1.add("b");
System.out.println(t1);
// 链表中只能存储一种数据类型
MyLinkedList<Integer> t2 = new MyLinkedList<>();
// 因为泛型只能用引用类型,因此想要存储整型数据就只能传入Integer
t2.add(1);
t2.add(2);
System.out.println(t2);
}
}
运行结果
泛型可以让我们根据自己的需求来进行一些数据的传递。
虽然我们在自己的代码中很少使用泛型,但是我们能够经常在原码中看到泛型。一些泛型也不是那么容易看懂,不知道时什么意思。如<? extends E>
和 <? super E>
。这两个都是经常能在 API 中看到的。那么这两种泛型时什么意思呢?
<? extends E>
是指 ? 这个类型是继承自 E 这个类型, ? 只能是 E 的子类或者 E 本身,即 E 是 ? 的上限。
<? super E>
是指 ? 这个类型是 E 类型的父类或者超类,? 只能是 E 的父类、超类或者 E 本身,即 E 是 ? 的下限。