在泛型出现之前,Java中的集合(如ArrayList)只能存储Object类型的对象,这意味着:

ClassCastException。泛型(Generics)是Java 5引入的一个重要特性,它允许我们在定义类、接口和方法时使用类型参数(Type Parameter),使得代码可以适用于多种数据类型,同时在编译期进行类型检查,从根本上解决了上述问题。
泛型类是最常见的泛型使用方式。我们在类名后面加上尖括号<>,里面声明一个或多个类型参数,通常用大写字母表示(如T、E、K、V)。### 基本语法
复制代码public class 类名<类型参数列表> {
// 可以使用类型参数定义字段、方法参数、返回值等
}
假设我们要设计一个“盒子”,可以装任何东西,但一旦装进去,取出时类型必须明确。
复制代码public class Box<T> {
private T content; public void set(T content) {
this.content = content;
} public T get() {
return content;
} public static void main(String[] args) {
// 存放String
Box<String> stringBox = new Box<>();
stringBox.set("Hello Generic");
String str = stringBox.get(); // 无需强制转换
System.out.println(str); // 存放Integer
Box<Integer> intBox = new Box<>();
intBox.set(123);
Integer num = intBox.get();
System.out.println(num);
}
}
关键点:
实例化时,我们指定了具体类型(如Box),编译器会替换掉所有T的位置。
如果没有指定类型,则默认为Object(原始类型,但不推荐)。
泛型类中的静态成员不能使用类的类型参数,因为静态成员属于类本身,而类型参数是在实例化时才确定的。
泛型方法是指在方法声明中定义自己的类型参数。它和泛型类没有必然联系——即使类不是泛型类,我们也可以定义泛型方法。
复制代码public <类型参数列表> 返回值类型 方法名(参数列表) {
// 方法体
}
复制代码public class GenericMethodDemo { // 这是一个泛型方法,类型参数为T
public static <T> List<T> arrayToList(T[] array) {
List<T> list = new ArrayList<>();
for (T element : array) {
list.add(element);
}
return list;
} public static void main(String[] args) {
String[] strArray = {"A", "B", "C"};
List<String> strList = arrayToList(strArray); // 类型推断自动识别
System.out.println(strList); Integer[] intArray = {1, 2, 3};
List<Integer> intList = arrayToList(intArray);
System.out.println(intList);
}
}
泛型接口与泛型类的定义类似,在接口名后加上类型参数。
复制代码public interface 接口名<类型参数列表> {
// 抽象方法可以使用类型参数
}
定义一个Producer<T>接口,用于生产某种类型的产品。
java
复制代码public interface Producer<T> {
T produce();
}// 实现类1:生产字符串
public class StringProducer implements Producer<String> {
@Override
public String produce() {
return "Hello, I'm a string.";
}
}// 实现类2:生产随机整数(实现时指定具体类型)
public class IntegerProducer implements Producer<Integer> {
@Override
public Integer produce() {
return new Random().nextInt(100);
}
}// 实现类3:仍然保留泛型(让子类再指定类型)
public class GenericProducer<T> implements Producer<T> {
private T item;
public GenericProducer(T item) { this.item = item; }
@Override
public T produce() { return item; }
}
实现方式总结:
StringProducer)。GenericProducer)。在深入泛型时,我们常常会遇到通配符?,它用于表示未知类型,通常用在方法参数中,以增加灵活性。
<?> 表示任意类型,但只能读不能写(除了null)。<? extends T> 表示T或T的子类,用于读取。<? super T> 表示T或T的父类,用于写入。 复制代码public static void printList(List<?> list) {
for (Object obj : list) { // 因为类型未知,只能用Object接收
System.out.println(obj);
}
}
extends。super。T(Type)、E(Element)、K(Key)、V(Value)、S,U等。通过这次学习,我深刻体会到泛型是Java静态类型系统的一大飞跃。它不仅让代码更安全(编译期检查),而且更通用(一份代码适应多种类型)。掌握泛型类、泛型方法和泛型接口的用法,以及通配符和类型擦除的底层原理,是写出高质量Java代码的基础。
在实际开发中,无论是集合框架、工具类还是设计模式(如工厂、建造者),泛型都无处不在。希望这篇博客能帮助你理清泛型的脉络,让你在编码时更加得心应手。