Appearance
🔷 泛型
泛型概述
泛型(Generics)是 Java 5 引入的特性,允许在定义类、接口和方法时使用类型参数,提高代码的类型安全性和可重用性。
泛型的好处
- 类型安全:编译时检查类型
- 代码复用:一个类可以处理多种类型
- 消除类型转换:自动处理类型转换
- 提高可读性:代码更清晰
泛型类
基本语法
java
// 泛型类定义
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
// 使用泛型类
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
String str = stringBox.getValue();
Box<Integer> intBox = new Box<>();
intBox.setValue(10);
Integer num = intBox.getValue();多个类型参数
java
// 多个类型参数
public class Pair<K, V> {
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;
}
}
// 使用
Pair<String, Integer> pair = new Pair<>("age", 25);
String key = pair.getKey();
Integer value = pair.getValue();泛型接口
基本语法
java
// 泛型接口
public interface List<T> {
void add(T item);
T get(int index);
int size();
}
// 实现泛型接口
public class ArrayList<T> implements List<T> {
private T[] items;
private int size;
@Override
public void add(T item) {
// 实现
}
@Override
public T get(int index) {
return items[index];
}
@Override
public int size() {
return size;
}
}泛型方法
基本语法
java
// 泛型方法
public class Util {
public static <T> T getFirst(T[] array) {
return array[0];
}
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
// 使用
String[] strArray = {"a", "b", "c"};
String first = Util.getFirst(strArray);
Integer[] intArray = {1, 2, 3};
Integer firstInt = Util.getFirst(intArray);类型通配符
上界通配符(? extends)
java
// 上界通配符:只能读取,不能写入
public void process(List<? extends Number> list) {
// 只能读取
Number num = list.get(0);
// ❌ 不能写入
// list.add(10); // 编译错误
}
// 使用
List<Integer> intList = Arrays.asList(1, 2, 3);
process(intList); // ✅ 可以
List<Double> doubleList = Arrays.asList(1.0, 2.0, 3.0);
process(doubleList); // ✅ 可以下界通配符(? super)
java
// 下界通配符:只能写入,不能读取
public void addNumber(List<? super Integer> list) {
list.add(10); // ✅ 可以写入
// ❌ 不能读取
// Integer num = list.get(0); // 编译错误
}
// 使用
List<Number> numberList = new ArrayList<>();
addNumber(numberList); // ✅ 可以
List<Object> objectList = new ArrayList<>();
addNumber(objectList); // ✅ 可以无界通配符(?)
java
// 无界通配符:只能读取,不能写入
public void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
// ❌ 不能写入
// list.add("item"); // 编译错误
}
// 使用
List<String> strList = Arrays.asList("a", "b", "c");
printList(strList); // ✅ 可以
List<Integer> intList = Arrays.asList(1, 2, 3);
printList(intList); // ✅ 可以类型擦除
类型擦除原理
java
// 编译前
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
// 编译后(类型擦除)
public class Box {
private Object value;
public void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}类型擦除的影响
java
// ❌ 不能创建泛型数组
// T[] array = new T[10]; // 编译错误
// ✅ 使用 Object 数组
Object[] array = new Object[10];
// ❌ 不能使用 instanceof
// if (obj instanceof Box<String>) { } // 编译错误
// ✅ 使用原始类型
if (obj instanceof Box) { } // 可以泛型限制
不能使用基本类型
java
// ❌ 错误:不能使用基本类型
// Box<int> box = new Box<>(); // 编译错误
// ✅ 正确:使用包装类
Box<Integer> box = new Box<>();不能创建泛型数组
java
// ❌ 错误:不能创建泛型数组
// List<String>[] lists = new List<String>[10]; // 编译错误
// ✅ 正确:使用通配符
List<?>[] lists = new List<?>[10];不能实例化类型参数
java
// ❌ 错误:不能实例化类型参数
// public class Box<T> {
// private T value = new T(); // 编译错误
// }
// ✅ 正确:使用反射或工厂方法
public class Box<T> {
private T value;
public Box(Class<T> clazz) throws Exception {
this.value = clazz.newInstance();
}
}完整示例
java
// 泛型类
public class GenericBox<T> {
private T value;
public GenericBox(T value) {
this.value = value;
}
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
// 泛型方法
public class GenericUtil {
public static <T> T getFirst(List<T> list) {
return list.isEmpty() ? null : list.get(0);
}
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
}
// 使用
public class GenericExample {
public static void main(String[] args) {
// 泛型类
GenericBox<String> stringBox = new GenericBox<>("Hello");
String str = stringBox.getValue();
GenericBox<Integer> intBox = new GenericBox<>(10);
Integer num = intBox.getValue();
// 泛型方法
List<String> strList = Arrays.asList("a", "b", "c");
String first = GenericUtil.getFirst(strList);
Integer max = GenericUtil.max(5, 10);
}
}最佳实践
1. 使用有意义的类型参数名
java
// ✅ 好的做法:使用有意义的名称
public class Box<T> { }
public class Map<K, V> { }
public class Pair<First, Second> { }
// ❌ 不好的做法:使用单个字母(除非是惯用)
public class Box<T1> { }2. 优先使用通配符
java
// ✅ 好的做法:使用通配符提高灵活性
public void process(List<? extends Number> list) { }
// ❌ 不好的做法:使用具体类型限制灵活性
public void process(List<Integer> list) { }3. 避免原始类型
java
// ❌ 不好的做法:使用原始类型
List list = new ArrayList();
// ✅ 好的做法:使用泛型
List<String> list = new ArrayList<>();下一步
掌握了泛型后,可以继续学习:
💡 提示:泛型提供了类型安全和代码复用,合理使用泛型可以编写更优雅的代码
