admin管理员组

文章数量:1446753

重学Java基础篇—Java泛型深度使用指南

一、泛型核心价值

类型安全代码复用的平衡艺术,主要解决以下问题:

  1. 避免强制类型转换错误(ClassCastException)
  2. 增强代码可读性和可维护性
  3. 实现通用算法和数据结构

二、基础用法规范

2.1 泛型类定义

代码语言:java复制
// 标准容器类示例
public class Box<T> {
    private T content;

    public void put(T item) {
        this.content = item;
    }

    public T get() {
        return content;
    }
}

// 使用示例
Box<String> stringBox = new Box<>();
stringBox.put("Hello");
String value = stringBox.get(); // 无需强制转型

2.2 泛型方法实现

代码语言:java复制
// 通用数组交换方法
public class ArrayUtils {
    public static <T> void swap(T[] array, int i, int j) {
        T temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

// 使用示例
String[] names = {"Alice", "Bob"};
ArrayUtils.swap(names, 0, 1);

三、类型参数约束

3.1 边界限定(Bounded Type)

代码语言:java复制
// 数值计算接口
public interface Calculator<T extends Number> {
    double calculate(T a, T b);
}

// 具体实现
public class AddCalculator implements Calculator<Double> {
    @Override
    public double calculate(Double a, Double b) {
        return a + b;
    }
}

3.2 多重边界

代码语言:java复制
// 同时实现Serializable和Comparable
public class MultiBound<T extends Comparable<T> & Serializable> {
    public void sort(List<T> list) {
        Collections.sort(list);
    }
}

四、通配符高级应用

4.1 三种通配符对比

类型

语法

适用场景

写入限制

无界通配符

<?>

只读操作

不能写入

上界通配符

<? extends T>

读取T及其子类对象

只能写入null

下界通配符

<? super T>

写入T及其父类对象

可以写入T对象

4.2 生产者-消费者模式

代码语言:java复制
// 生产者使用extends
public static void processProducers(List<? extends Number> list) {
    for (Number n : list) {
        System.out.println(n.doubleValue());
    }
}

// 消费者使用super
public static void addIntegers(List<? super Integer> list) {
    for (int i = 0; i < 5; i++) {
        list.add(i);
    }
}

五、类型擦除应对策略

5.1 运行时类型信息保留

代码语言:java复制
// 通过Class对象传递类型信息
public class TypeSafeMap {
    private Map<Class<?>, Object> map = new HashMap<>();

    public <T> void put(Class<T> type, T instance) {
        map.put(type, instance);
    }

    public <T> T get(Class<T> type) {
        return type.cast(map.get(type));
    }
}

// 使用示例
TypeSafeMap safeMap = new TypeSafeMap();
safeMap.put(String.class, "Secret");
String value = safeMap.get(String.class);

5.2 泛型数组创建

代码语言:java复制
// 正确创建泛型数组方法
public class ArrayFactory {
    @SuppressWarnings("unchecked")
    public static <T> T[] createArray(Class<T> type, int size) {
        return (T[]) Array.newInstance(type, size);
    }
}

// 使用示例
String[] strings = ArrayFactory.createArray(String.class, 10);

六、典型应用场景

6.1 通用DAO接口

代码语言:java复制
public interface BaseDao<T, ID> {
    T findById(ID id);
    List<T> findAll();
    void save(T entity);
    void delete(ID id);
}

// 具体实现
public class UserDao implements BaseDao<User, Long> {
    // 实现接口方法...
}

6.2 事件总线系统

代码语言:java复制
public class EventBus {
    private Map<Class<?>, List<Consumer<?>>> handlers = new HashMap<>();

    public <T> void subscribe(Class<T> eventType, Consumer<T> handler) {
        handlersputeIfAbsent(eventType, k -> new ArrayList<>()).add(handler);
    }

    @SuppressWarnings("unchecked")
    public <T> void publish(T event) {
        List<Consumer<?>> consumers = handlers.get(event.getClass());
        if (consumers != null) {
            consumers.forEach(consumer -> ((Consumer<T>) consumer).accept(event));
        }
    }
}

七、常见错误及修正

7.1 原生类型使用

代码语言:java复制
// 错误示例
List rawList = new ArrayList();
rawList.add("String");
rawList.add(10); // 编译通过但运行危险

// 修正方案
List<String> safeList = new ArrayList<>();
safeList.add("Hello");
// safeList.add(10); // 编译错误

7.2 泛型数组初始化

代码语言:java复制
// 错误示例
T[] array = new T[10]; // 编译错误

// 正确方法
T[] array = (T[]) new Object[10]; // 需配合类型转换

八、最佳实践总结

  1. 命名规范:使用有意义的类型参数名称(如<K, V>优于<T, U>
  2. 边界控制:尽可能使用最严格的类型约束
  3. 通配符策略: • PECS原则(Producer-Extends, Consumer-Super) • 返回值不使用通配符
  4. 类型安全: • 优先使用泛型方法而非原生类型 • 利用@SuppressWarnings时添加明确注释
  5. 文档规范:在复杂泛型类中增加类型参数说明

九、扩展知识接口

9.1 获取泛型参数类型

代码语言:java复制
public abstract class TypeToken<T> {
    private final Type type;

    protected TypeToken() {
        Type superClass = getClass().getGenericSuperclass();
        this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public Type getType() {
        return type;
    }
}

// 使用示例
Type stringType = new TypeToken<String>() {}.getType();

9.2 泛型与反射结合

代码语言:java复制
public class GenericReflection {
    public static void printTypeParameters(Class<?> clazz) {
        TypeVariable<?>[] typeParams = clazz.getTypeParameters();
        for (TypeVariable<?> param : typeParams) {
            System.out.println("Type parameter: " + param.getName());
            for (Type bound : param.getBounds()) {
                System.out.println("  Bound: " + bound.getTypeName());
            }
        }
    }
}

// 分析List接口
GenericReflection.printTypeParameters(List.class);

通过合理应用泛型技术,可以显著提升代码的健壮性和可维护性。建议在复杂泛型场景中使用IDE的代码检查功能,并配合单元测试验证类型安全性。随着Java版本的演进(如引入var),泛型的使用方式也在不断优化,需要持续关注语言新特性。

本文标签: 重学Java基础篇Java泛型深度使用指南