Java 泛型详解:从入门到实战

一、什么是泛型?

泛型(Generics)是 Java 5 引入的重要特性之一,它允许在定义类、接口和方法时使用类型参数化。通过泛型,我们可以在编写代码时不指定具体类型,而是在使用时再传入具体的类型。

示例:没有泛型的集合操作

Map map = new HashMap();
map.put("key", "value");
String s = (String) map.get("key"); // 必须强制类型转换

如果有人插入了 Integer 类型的值,运行时会抛出 ClassCastException

使用泛型后:

Map map = new HashMap<>();
String s = map.get("key"); // 不需要强制类型转换

泛型帮助我们在编译期就发现类型错误,提高了程序的安全性和可读性


✅ 二、泛型的优势

优势 描述
类型安全 编译器会在编译阶段检查类型是否匹配,避免运行时异常
消除强制类型转换 提高代码可读性和安全性
代码复用 同一套逻辑适配多种数据类型
更好的性能表现 减少不必要的类型检查与转换

三、泛型的基本用法

1. 定义泛型类

public class Box {
    private T item;

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

    public T getItem() {
        return item;
    }
}

使用方式:

Box stringBox = new Box<>();
stringBox.setItem("Hello");
String content = stringBox.getItem(); // 不需要强转

2. 定义泛型接口

public interface Container {
    void add(T item);
    T get(int index);
}

实现该接口的类也需要使用泛型:

public class ListContainer implements Container {
    private List list = new ArrayList<>();

    public void add(T item) {
        list.add(item);
    }

    public T get(int index) {
        return list.get(index);
    }
}

3. 定义泛型方法

public class Util {
    public static  T getFirst(List list) {
        return list.isEmpty() ? null : list.get(0);
    }
}

调用方式:

List names = Arrays.asList("Alice", "Bob");
String first = Util.getFirst(names); // 自动推断为 String 类型

四、泛型命名规范

符号 含义
T Type,通用类型
E Element,集合元素
K Key,键
V Value,值
N Number,数字类型

⚠️ 五、泛型的限制与注意事项

1. 泛型不是协变的

List intList = new ArrayList<>();
List numberList = intList; // ❌ 编译错误!

这是为了防止将 Float 添加进 List 中,破坏类型安全。

2. 使用通配符 ?

当不需要关心具体类型时,可以使用通配符:

public void printList(List list) {
    for (Object obj : list) {
        System.out.println(obj);
    }
}

还可以结合上下限使用:

  • :表示 T 或其子类
  • :表示 T 或其父类

3. 泛型不能使用基本类型

只能使用包装类型,如 IntegerDouble 等,不能直接使用 intdouble

4. 类型擦除(Type Erasure)

Java 的泛型是通过类型擦除实现的,即在运行时泛型信息会被擦除:

List list1 = new ArrayList<>();
List list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass()); // true

这意味着泛型只存在于编译阶段。


六、自定义泛型类示例

下面是一个简单的泛型容器类 Lhist

public class Lhist {
    private V[] array;
    private int size;

    public Lhist(int capacity) {
        array = (V[]) new Object[capacity];
    }

    public void add(V value) {
        if (size == array.length)
            throw new IndexOutOfBoundsException();
        array[size++] = value;
    }

    public V get(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException();
        return array[index];
    }

    public int size() {
        return size;
    }
}

使用方式:

Lhist stringList = new Lhist<>(10);
stringList.add("Hello");
System.out.println(stringList.get(0)); // 输出 Hello

七、Java 类库中的泛型应用

Java 标准库从 Java 5 开始全面支持泛型,尤其是集合框架:

  • Collection
  • List
  • Set
  • Map
  • Queue

例如:

List names = new ArrayList<>();
names.add("Tom");
String name = names.get(0); // 无需强转

还广泛使用了通配符和边界限定:

public boolean addAll(Collection c);

八、总结

特点 描述
类型安全 在编译期检查类型,避免运行时异常
消除强制类型转换 提高代码可读性和安全性
代码复用 一份逻辑适配多种类型
通配符 支持灵活的类型匹配(?? extends T? super T
类型擦除 运行时无泛型信息,仅保留原始类型

参考资料 / 推荐阅读

  • Oracle 官方文档:Generics
  • 《Effective Java》第 5 条:避免不必要的泛型使用
  • 《Java 编程思想》泛型章节

如果你觉得这篇文章对你有帮助,欢迎点赞 + 收藏 + 关注我,后续将持续更新 Java 技术干货内容!

你可能感兴趣的:(Java 泛型详解:从入门到实战)