什么是泛型类?
泛型类是带有类型参数的类。简单来说,就是把泛型参数作为类的一部分来定义。泛型类最常见的用途是创建可重用的容器类。
生活比喻
泛型类就像一个万能收纳盒。你可以把它当成"文件盒"、"药盒"、"工具盒"...每个盒子的结构一样,但里面装的东西不同。泛型类就是这样的模具,给你什么类型参数,它就变成什么类型的容器。
泛型类的定义和使用
基础泛型类
// 定义泛型类 - 类名后面跟
class Box {
private T content;
public void put(T item) {
this.content = item;
}
public T get() {
return content;
}
}
// 使用时指定具体类型
Box stringBox = new Box<>();
stringBox.put("Hello World");
String message = stringBox.get(); // 自动是String类型
Box intBox = new Box<>();
intBox.put(123);
Integer number = intBox.get(); // 自动是Integer类型
多类型参数的泛型类
泛型类可以有多个类型参数,这在Map等场景中很常用:
// 两个类型参数的泛型类
class Pair {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
// 交换功能
public Pair swap() {
return new Pair<>(value, key);
}
}
// 使用
Pair score = new Pair<>("数学", 95);
System.out.println(score.getKey() + ": " + score.getValue());
Pair swapped = score.swap();
System.out.println(swapped.getKey() + ": " + swapped.getValue());
泛型接口
接口同样可以是泛型的,让实现类提供具体类型:
// 定义泛型接口
interface Container {
void add(E element);
E get(int index);
int size();
boolean isEmpty();
}
// 实现泛型接口 - 指定具体类型
class StringContainer implements Container {
private String[] elements;
private int size = 0;
public StringContainer(int capacity) {
elements = new String[capacity];
}
@Override
public void add(String element) {
if (size < elements.length) {
elements[size++] = element;
}
}
@Override
public String get(int index) {
if (index >= 0 && index < size) {
return elements[index];
}
return null;
}
@Override
public int size() { return size; }
@Override
public boolean isEmpty() { return size == 0; }
}
// 实现泛型接口 - 保留泛型
class GenericContainer implements Container {
private Object[] elements;
private int size = 0;
public GenericContainer(int capacity) {
elements = new Object[capacity];
}
@Override
public void add(E element) {
if (size < elements.length) {
elements[size++] = element;
}
}
@Override
public E get(int index) {
if (index >= 0 && index < size) {
return (E) elements[index];
}
return null;
}
@Override
public int size() { return size; }
@Override
public boolean isEmpty() { return size == 0; }
}
泛型类的类型限制
有时候你需要限制泛型类型参数的范围,这时可以使用泛型限定:
上界限定(extends)
// 限制T必须是Number或其子类
class NumberBox {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
// 现在可以安全调用Number的方法
public double toDouble() {
return value.doubleValue();
}
}
// 合法
NumberBox intBox = new NumberBox<>();
NumberBox doubleBox = new NumberBox<>();
// 非法 - String不是Number的子类
// NumberBox stringBox = new NumberBox<>(); // 编译错误!
多个上界
// T必须同时实现Comparable和Serializable
class ComparableBox & Serializable> {
private T item;
public void sortIfPossible(T other) {
if (item.compareTo(other) > 0) {
System.out.println("item > other");
}
}
}
泛型类的继承
泛型类可以继承泛型或非泛型类,也可以被泛型或非泛型类继承:
// 父类
class Animal { }
// 子类保留父类的泛型
class Dog extends Animal { }
// 子类具体化泛型
class StringDog extends Animal { }
// 子类添加新的泛型参数
class SpecialDog extends Dog {
private R attribute;
}
泛型类的构造函数
泛型类的构造函数不需要重复声明泛型参数:
class Stack {
private T[] array;
private int top;
// 构造函数不需要,因为T已经在类声明中声明
public Stack(int capacity) {
this.array = (T[]) new Object[capacity];
this.top = 0;
}
public void push(T item) {
if (top < array.length) {
array[top++] = item;
}
}
public T pop() {
if (top > 0) {
return array[--top];
}
return null;
}
}
// 使用
Stack intStack = new Stack<>(10);
intStack.push(1);
intStack.push(2);
System.out.println(intStack.pop()); // 2
静态变量和泛型
重要:静态成员不能使用类的泛型类型参数
class WrongExample {
private T instance; // OK - 实例变量可以用T
// private static T staticVar; // 错误! 静态变量不能用T
// 静态方法可以自己定义泛型参数
public static void print(E item) {
System.out.println(item);
}
// 静态方法也可以使用类的泛型(但不推荐)
public static S getDefault(Supplier supplier) {
return supplier.get();
}
}
小结
- 泛型类在类名后使用<T>声明类型参数
- 可以使用多个类型参数如<K, V>
- 泛型接口与泛型类的用法相同
- 使用extends限定限制类型参数的范围
- 静态成员不能使用类的泛型类型参数
- 构造函数不需要重复声明泛型参数