致敬读者
博主相关
文章前言
泛型(Generics)是 Java 中非常重要的特性,它让代码更安全、更灵活。下面用通俗易懂的方式为你讲解,包含代码示例和核心概念。
问题:假设你要写一个可以存放任何类型数据的容器(比如一个盒子)。没有泛型时,代码可能这样写:
class Box {
private Object data; // 用 Object 存储任意类型
public void setData(Object data) {
this.data = data;
}
public Object getData() {
return data;
}
}
缺陷:
泛型的解决方案:让容器在定义时声明它能存储的数据类型。
Box<String> box = new Box<>(); // 只能存 String
box.setData("Hello"); // 正确
// box.setData(123); // 编译报错!
String data = box.getData(); // 无需强制转换
在类名后加
,T
是类型参数(可以是任意标识符,如E
, K
, V
等)。
class Box<T> { // T 表示“某种类型”
private T data;
public void setData(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
创建对象时指定具体类型:
Box<String> stringBox = new Box<>(); // 存储 String
Box<Integer> intBox = new Box<>(); // 存储 Integer
即使类不是泛型,方法也可以独立声明泛型:
public class Utils {
// 泛型方法:在返回类型前加
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
// 使用
Integer[] intArray = {1, 2, 3};
Utils.printArray(intArray); // 自动推断类型为 Integer
?
用于处理未知类型,常见于方法参数或集合操作。
>
表示接受任何类型:
public static void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
extends T>
表示类型是T
或其子类:
// 只能读取元素(因为元素是 Animal 或其子类)
public static void processAnimals(List<? extends Animal> animals) {
for (Animal animal : animals) {
animal.eat();
}
}
super T>
表示类型是T
或其父类:
// 可以写入元素(因为容器是 T 的父类)
public static void addNumbers(List<? super Integer> list) {
list.add(123); // 允许添加 Integer
}
extends T>
,只能读取。 super T>
,只能写入。Java 泛型在编译后会被擦除为原始类型(如Object
),这是为了兼容旧版本 Java。例如:
List<String> list = new ArrayList<>();
// 编译后实际是:List list = new ArrayList();
影响:
T
的实际类型)。new T[]
)。List
错误,要用List
)。不能实例化类型参数:
// 错误!new T() 是非法的
T data = new T();
静态成员不能使用泛型类型:
class Box<T> {
// 错误!静态变量不能是泛型
private static T staticData;
}
泛型与继承的关系:
List
不是 List
的子类。ArrayList
是 List
的子类。ArrayList
、HashMap
)。Collections
中的泛型方法)。class Stack<T> {
private List<T> elements = new ArrayList<>();
public void push(T element) {
elements.add(element);
}
public T pop() {
if (elements.isEmpty()) {
throw new EmptyStackException();
}
return elements.remove(elements.size() - 1);
}
}
// 使用
Stack<Integer> stack = new Stack<>();
stack.push(1);
int num = stack.pop(); // 无需强制转换
定义泛型,?
处理未知类型。掌握泛型后,你将能写出更健壮、更灵活的 Java 代码!
文末寄语