1. 泛型概述
1.1 什么是泛型
泛型(Generics)是JDK 5引入的特性,允许在定义类、接口和方法时使用类型参数,提供编译时类型安全检查,避免运行时类型转换异常。
1.2 泛型的好处
-
类型安全:编译时检查类型
-
消除强制转换:代码更简洁
-
代码重用:编写通用的算法和数据结构
-
更好的可读性:明确类型约束
2. 泛型基础语法
2.1 泛型类
java
// 单个类型参数
public class Box<T> {
private T content;
public Box(T content) {
this.content = content;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
// 多个类型参数
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; }
}
// 使用示例
Box<String> stringBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(100);
Pair<String, Integer> pair = new Pair<>("age", 25);
2.2 泛型接口
java
// 定义泛型接口
public interface Repository<T> {
void save(T entity);
T findById(String id);
List<T> findAll();
}
// 实现泛型接口(指定具体类型)
public class UserRepository implements Repository<User> {
@Override
public void save(User entity) { /* 实现 */ }
@Override
public User findById(String id) { /* 实现 */ }
@Override
public List<User> findAll() { /* 实现 */ }
}
// 实现泛型接口(保持泛型)
public class GenericRepository<T> implements Repository<T> {
@Override
public void save(T entity) { /* 实现 */ }
@Override
public T findById(String id) { /* 实现 */ }
@Override
public List<T> findAll() { /* 实现 */ }
}
2.3 泛型方法
java
public class GenericMethods {
// 普通类中的泛型方法
public <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
// 带返回值的泛型方法
public <T> T getFirstElement(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
// 多个类型参数的泛型方法
public <K, V> void printPair(K key, V value) {
System.out.println(key + " -> " + value);
}
// 静态泛型方法
public static <T> boolean isNull(T obj) {
return obj == null;
}
}
// 使用示例
GenericMethods gm = new GenericMethods();
String[] strings = {"A", "B", "C"};
Integer[] numbers = {1, 2, 3};
gm.printArray(strings); // 类型推断
gm.<String>printArray(strings); // 显式指定类型
gm.printArray(numbers);
3. 类型参数约束
3.1 上界通配符(extends)
java
// 类型参数必须是Number或其子类
public class NumberContainer<T extends Number> {
private T number;
public NumberContainer(T number) {
this.number = number;
}
public double getSquare() {
return number.doubleValue() * number.doubleValue();
}
}
// 实现多个接口
public class MultiBound<T extends Number & Comparable<T> & Serializable> {
// T必须是Number的子类,并且实现Comparable和Serializable接口
}
// 使用示例
NumberContainer<Integer> intContainer = new NumberContainer<>(10);
NumberContainer<Double> doubleContainer = new NumberContainer<>(3.14);
// NumberContainer<String> stringContainer; // 编译错误
3.2 通配符(Wildcards)
3.2.1 无界通配符(?)
java
public class WildcardDemo {
// 接受任何类型的List
public static void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
// 只能获取为Object,不能添加(除了null)
public static void processList(List<?> list) {
// list.add("string"); // 编译错误
list.add(null); // 可以添加null
Object obj = list.get(0); // 可以读取为Object
}
}
3.2.2 上界通配符(? extends)
java
public class UpperBoundedWildcard {
// 接受Number及其子类的List
public static double sumOfList(List<? extends Number> list) {
double sum = 0.0;
for (Number num : list) {
sum += num.doubleValue();
}
return sum;
}
// 可以读取为Number,不能添加
public static void processNumbers(List<? extends Number> list) {
Number num = list.get(0); // 可以读取
// 以下都会编译错误
// list.add(new Integer(10));
// list.add(new Double(3.14));
// list.add(new Object());
}
}
3.2.3 下界通配符(? super)
java
public class LowerBoundedWildcard {
// 接受Integer及其父类的List
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 5; i++) {
list.add(i);
}
}
// 可以添加Integer及其子类,读取为Object
public static void processIntegers(List<? super Integer> list) {
list.add(10); // 可以添加Integer
list.add(Integer.valueOf(20)); // 可以添加Integer
// list.add(new Object()); // 编译错误
Object obj = list.get(0); // 只能读取为Object
// Integer num = list.get(0); // 编译错误
}
}
4. 类型擦除与桥方法
4.1 类型擦除原理
java
// 编译前
public class GenericClass<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
// 编译后(类型擦除)
public class GenericClass {
private Object value;
public void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}
// 有界类型的擦除
public class BoundedClass<T extends Number> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
// 编译后
public class BoundedClass {
private Number value;
public void setValue(Number value) {
this.value = value;
}
public Number getValue() {
return value;
}
}
4.2 桥方法(Bridge Methods)
java
// 编译前
public class Node<T> {
public T data;
public void setData(T data) {
this.data = data;
}
}
public class IntegerNode extends Node<Integer> {
@Override
public void setData(Integer data) {
super.setData(data);
}
}
// 编译后会产生桥方法
public class IntegerNode extends Node {
// 重写的方法
public void setData(Integer data) {
super.setData(data);
}
// 编译器生成的桥方法
public void setData(Object data) {
setData((Integer) data); // 类型检查和转换
}
}
5. 泛型与数组
5.1 不能创建泛型数组
java
public class ArrayIssues {
// 以下代码编译错误
// List<String>[] arrayOfLists = new List<String>[10];
// 可以创建通配符类型的数组
List<?>[] arrayOfLists = new List<?>[10];
// 可以使用ArrayList代替数组
List<List<String>> listOfLists = new ArrayList<>();
// 类型安全的替代方案
@SuppressWarnings("unchecked")
public <T> T[] createGenericArray(Class<T> type, int size) {
return (T[]) Array.newInstance(type, size);
}
}
5.2 可变参数与泛型
java
public class VarargsAndGenerics {
// 可变参数实际上是数组,会有类型安全问题
@SafeVarargs // JDK 7+,表示方法不会对可变参数执行不安全操作
public static <T> List<T> createList(T... elements) {
List<T> list = new ArrayList<>();
for (T element : elements) {
list.add(element);
}
return list;
}
// 使用示例
List<String> strings = createList("A", "B", "C");
List<Integer> numbers = createList(1, 2, 3);
}
6. 实际应用示例
6.1 泛型缓存
java
public class GenericCache<K, V> {
private final Map<K, V> cache = new ConcurrentHashMap<>();
public void put(K key, V value) {
cache.put(key, value);
}
public V get(K key) {
return cache.get(key);
}
public boolean contains(K key) {
return cache.containsKey(key);
}
public void remove(K key) {
cache.remove(key);
}
public Set<K> keySet() {
return cache.keySet();
}
}
6.2 泛型DAO模式
java
// 基础实体接口
public interface Entity {
Long getId();
void setId(Long id);
}
// 泛型DAO接口
public interface GenericDAO<T extends Entity> {
void save(T entity);
void update(T entity);
void delete(Long id);
T findById(Long id);
List<T> findAll();
List<T> findByCriteria(String criteria, Object... params);
}
// 泛型DAO实现
public abstract class GenericDAOImpl<T extends Entity> implements GenericDAO<T> {
protected Class<T> entityClass;
public GenericDAOImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
@Override
public T findById(Long id) {
// 使用反射创建实例
try {
T entity = entityClass.getDeclaredConstructor().newInstance();
entity.setId(id);
// 实际应该从数据库加载
return entity;
} catch (Exception e) {
throw new RuntimeException("Failed to create entity", e);
}
}
// 其他方法实现...
}
// 具体实体类
public class User implements Entity {
private Long id;
private String name;
private String email;
// getters and setters...
}
// 具体DAO
public class UserDAO extends GenericDAOImpl<User> {
public UserDAO() {
super(User.class);
}
// 可以添加User特有的方法
public User findByEmail(String email) {
// 实现...
return null;
}
}
6.3 泛型工厂模式
java
// 产品接口
public interface Product {
void use();
}
// 具体产品
public class Computer implements Product {
@Override
public void use() {
System.out.println("Using computer");
}
}
public class Phone implements Product {
@Override
public void use() {
System.out.println("Using phone");
}
}
// 泛型工厂接口
public interface Factory<T extends Product> {
T create();
}
// 具体工厂
public class ComputerFactory implements Factory<Computer> {
@Override
public Computer create() {
return new Computer();
}
}
public class PhoneFactory implements Factory<Phone> {
@Override
public Phone create() {
return new Phone();
}
}
// 使用工厂
public class FactoryClient {
public static void main(String[] args) {
Factory<Computer> computerFactory = new ComputerFactory();
Computer computer = computerFactory.create();
computer.use();
Factory<Phone> phoneFactory = new PhoneFactory();
Phone phone = phoneFactory.create();
phone.use();
}
}
7. 泛型的最佳实践
7.1 命名约定
-
E - Element(集合中的元素)
-
K - Key(键)
-
V - Value(值)
-
N - Number(数字)
-
T - Type(类型)
-
S, U, V - 第二、第三、第四类型
7.2 使用建议
java
public class GenericBestPractices {
// 1. 优先使用泛型方法,而不是原始类型
// 不好
public static List getRawList() {
return new ArrayList();
}
// 好
public static <T> List<T> getGenericList() {
return new ArrayList<>();
}
// 2. 使用有界通配符增加API灵活性
// 接受任何Number子类的集合
public static double sum(Collection<? extends Number> numbers) {
return numbers.stream()
.mapToDouble(Number::doubleValue)
.sum();
}
// 3. 避免在静态成员中使用类型参数
// 错误:静态成员不能使用类的类型参数
// private static T staticField;
// 正确:静态方法可以使用自己的类型参数
public static <T> T firstElement(List<T> list) {
return list.get(0);
}
// 4. 使用Class<T>参数进行类型安全的实例化
public static <T> T createInstance(Class<T> clazz) throws Exception {
return clazz.getDeclaredConstructor().newInstance();
}
// 5. 合理使用@SuppressWarnings注解
@SuppressWarnings("unchecked")
public <T> T[] toArray(List<T> list) {
// 已知安全的类型转换
return (T[]) list.toArray();
}
}
7.3 常见陷阱与解决方案
java
public class GenericPitfalls {
// 陷阱1:不能实例化类型参数
public <T> void createInstanceError() {
// T obj = new T(); // 编译错误
}
// 解决方案:使用Class对象
public <T> T createInstance(Class<T> clazz) throws Exception {
return clazz.newInstance();
}
// 陷阱2:不能创建泛型数组
public <T> void createArrayError() {
// T[] array = new T[10]; // 编译错误
}
// 解决方案1:使用ArrayList
public <T> List<T> createList() {
return new ArrayList<>();
}
// 解决方案2:使用类型安全的反射
public <T> T[] createArray(Class<T> type, int size) {
@SuppressWarnings("unchecked")
T[] array = (T[]) Array.newInstance(type, size);
return array;
}
// 陷阱3:静态上下文不能使用类型参数
// 解决方案:在静态方法中定义自己的类型参数
public static <T> boolean isEmpty(Collection<T> collection) {
return collection == null || collection.isEmpty();
}
}
8. JDK中的泛型应用
8.1 集合框架中的泛型
java
public class CollectionsExample {
public static void main(String[] args) {
// List使用泛型
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
stringList.add("World");
// stringList.add(123); // 编译错误
// Map使用泛型
Map<String, Integer> wordCount = new HashMap<>();
wordCount.put("apple", 5);
wordCount.put("banana", 3);
// Set使用泛型
Set<Integer> numberSet = new HashSet<>();
numberSet.add(1);
numberSet.add(2);
numberSet.add(3);
// 使用Collections工具类
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> synchronizedList = Collections.synchronizedList(numbers);
// 使用Stream API(大量使用泛型)
List<String> filtered = stringList.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
}
}
8.2 函数式接口与泛型
java
public class FunctionalGenerics {
// 自定义泛型函数式接口
@FunctionalInterface
public interface Transformer<T, R> {
R transform(T input);
}
// 使用示例
public static void main(String[] args) {
// 字符串转整数
Transformer<String, Integer> stringToInt = Integer::parseInt;
// 整数转字符串
Transformer<Integer, String> intToString = String::valueOf;
// 使用Stream的map方法(泛型应用)
List<String> numbers = Arrays.asList("1", "2", "3");
List<Integer> ints = numbers.stream()
.map(stringToInt::transform)
.collect(Collectors.toList());
System.out.println(ints); // [1, 2, 3]
}
}
9. 高级主题:泛型与反射
java
public class GenericReflection {
// 获取泛型类型信息
public static void analyzeGenericType() {
// 创建带泛型的List
List<String> stringList = new ArrayList<>();
// 获取Class对象
Class<?> listClass = stringList.getClass();
System.out.println("Class: " + listClass.getName()); // java.util.ArrayList
// 获取泛型父类信息
Type genericSuperclass = listClass.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = pt.getActualTypeArguments();
System.out.println("Generic superclass type arguments: " +
Arrays.toString(actualTypeArguments));
}
// 获取泛型接口信息
Type[] genericInterfaces = listClass.getGenericInterfaces();
for (Type type : genericInterfaces) {
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
System.out.println("Interface: " + pt.getRawType());
System.out.println("Type arguments: " +
Arrays.toString(pt.getActualTypeArguments()));
}
}
}
// 创建泛型类型的实例
public static <T> T createGenericInstance(Class<T> clazz) throws Exception {
return clazz.getDeclaredConstructor().newInstance();
}
// 处理泛型方法
public static class GenericMethodHolder {
public <T> T genericMethod(Class<T> clazz) throws Exception {
return clazz.getDeclaredConstructor().newInstance();
}
}
// 获取方法的泛型返回类型
public static void analyzeMethodReturnType() throws Exception {
Method method = GenericMethodHolder.class.getMethod("genericMethod", Class.class);
Type returnType = method.getGenericReturnType();
if (returnType instanceof TypeVariable) {
TypeVariable<?> typeVariable = (TypeVariable<?>) returnType;
System.out.println("Return type is type variable: " + typeVariable.getName());
System.out.println("Bounds: " + Arrays.toString(typeVariable.getBounds()));
}
}
}
10. 总结
10.1 核心要点
-
类型安全:编译时检查,避免运行时ClassCastException
-
代码复用:编写通用的算法和数据结构
-
消除强制转换:使代码更简洁清晰
-
类型擦除:理解Java泛型的实现机制
10.2 使用原则
-
尽量使用泛型:提高代码类型安全性
-
合理使用通配符:增加API灵活性
-
避免原始类型:失去类型安全检查
-
注意类型擦除的影响:运行时无法获取泛型类型信息
-
使用有界类型参数:增加类型约束
10.3 适用场景
-
集合类:List<T>, Map<K, V>, Set<T>等
-
工具类:通用算法、缓存、工厂等
-
DAO/Repository模式:数据访问层
-
回调/事件处理:通用处理器
-
框架开发:提供扩展点和插件机制
掌握泛型是Java高级编程的重要基础,能够显著提高代码的质量和可维护性。