1. 核心原理
类型参数化 泛型允许我们在定义类、接口或方法时指定一个或多个类型参数。例如:
public class Box {
private T element;
public void setElement(T element) {
this.element = element;
}
public T getElement() {
return this.element;
}
}
类型擦除 Java 在编译时会移除泛型类型信息,将所有泛型类型替换为具体的类型(通常是 Object)。虽然这在运行时失去了类型信息,但通过编译时的检查确保了类型安全。
边界推导与上下界 为了确保类型兼容性,泛型可以使用上限(extends)和下限(super)来定义类型关系。例如:
- List extends t> 表示列表中的元素是 T 的子类型。
- List super t> 表示列表中的元素是 T 或其父类型的实例。
2. 特性
代码复用 泛型允许编写一次代码,适用于多种数据类型。例如,一个排序方法可以处理所有可比较的类型,而无需为每个具体类型分别实现。
类型安全 通过编译时检查,避免了运行时类型转换错误(ClassCastException),确保操作在正确的类型范围内进行。
提高可维护性与可读性 使用有意义的泛型变量名(如 T 表示某种对象)使代码更易理解,减少了注释需求,并提高了代码质量。
3. 使用方法
定义泛型类
public class Box {
// 定义一个带有类型参数 T 的类
}
使用泛型变量
在类的方法中使用 T:
public void addElement(T element) {
// 操作 element,确保类型正确性
}
public T retrieveElement() {
return element;
}
构造泛型对象
必须提供实际的类型参数来构造泛型对象:
Box stringBox = new Box<>();
Box integerBox = new Box<>();
类型推断与菱形语法
Java 可以根据上下文自动推断泛型类型,简化代码。例如:
Box box = new Box<>(); // 推断出 T 为 String
List list = new ArrayList<>(); // 菱形语法,省略 <> 内的内容
处理多个类型参数
使用逗号分隔多个类型参数,并可指定它们的边界:
public class Pair<K, V extends Comparable> {
K key;
V value;
public void setKey(K key) { this.key = key; }
// ...
}
4. 实际应用案例
排序方法
实现一个适用于所有可比较类型的排序方法:
public static <T extends Comparable> void sort(T[] array) {
Arrays.sort(array);
}
泛型接口与实现类
定义一个处理不同类型集合的泛型接口:
interface Processor {
void process(List elements);
}
public class DefaultProcessor implements Processor {
@Override
public void process(List elements) {
// 处理字符串列表
}
}
上下界的使用
确保类型兼容性:
public class Collection {
private U value;
public void setValue(U value) { this.value = value; }
public U getValue() { return value; }
}
5. 注意事项
- 基本数据类型的包装:泛型不能直接用于基本数据类型,必须使用其对应的包装类(如 Integer)。
- 通配符的使用:小心处理上下界和通配符,以避免运行时错误。例如:
- List<? extends Number> list; // 允许从任意Number子类型列表中读取
List<? super Integer> list; // 允许向任何可以容纳Integer的列表中写入 - 可变参数与泛型结合:在方法参数中,必须确保所有可变参数具有相同的泛型类型。
总结
Java 泛型通过引入类型参数和边界检查,提供了强大的代码复用性和类型安全性。理解其核心原理、特性及使用方法是高效开发的关键。正确应用泛型不仅提高了代码的可维护性,还减少了潜在的运行时错误风险。
本文暂时没有评论,来添加一个吧(●'◡'●)