Java 集合与泛型完整讲解

一、整体关系
泛型是 Java 集合体系的语法基础:集合本质是存储一组对象的容器,早期Object类型集合存在类型强制转换、类型安全隐患;泛型(JDK5引入) 给集合约束元素类型,实现编译期类型检查、消除强制类型转换、提升代码复用性。
二、Java 集合体系(核心架构)
集合分为两大派系:Collection(单列集合,存单个元素)、Map(双列集合,键值对 key-value),全部位于java.util包。

  1. Collection 单列集合根接口
    Collection
    ├─ List(有序可重复,索引访问)
    │ ├─ ArrayList:数组实现,查询快、增删尾部快,线程不安全
    │ ├─ LinkedList:双向链表,头尾增删快,随机查询慢
    │ └─ Vector:线程安全数组,效率低(过时)
    ├─ Set(无序不可重复)
    │ ├─ HashSet:哈希表实现,无序,基于 hashCode+equals 去重
    │ ├─ LinkedHashSet:哈希+链表,保留插入顺序
    │ └─ TreeSet:红黑树,元素可排序(实现Comparable/传Comparator)
    └─ Queue(队列,先进先出)
    ├─ ArrayDeque:数组双端队列
    └─ PriorityQueue:优先级队列(堆结构)
  2. Map 双列集合根接口(不继承Collection)
    Map
    ├─ HashMap:哈希表,键无序,JDK8 数组+链表+红黑树,线程不安全
    ├─ LinkedHashMap:保留键插入顺序
    ├─ TreeMap:红黑树,按键排序
    ├─ Hashtable:古老线程安全Map,效率低(过时)
    └─ Properties:键值都是String,读写配置文件
    三、为什么需要泛型?(无泛型的痛点)
    无泛型(JDK5之前)
    集合默认存储Object,任意对象都能存入,取出必须强转,极易出现ClassCastException运行时异常:
    List list = new ArrayList();
    list.add("abc");
    list.add(123); // 混入Integer
    String s = (String) list.get(1); // 运行时报类型转换异常
    引入泛型后
    编译阶段强制校验存入元素类型,取出无需强转,把运行时错误提前到编译期:
    List list = new ArrayList<>(); // 泛型约束只能存String
    list.add("abc");
    // list.add(123); 编译直接报错,杜绝类型错误
    String s = list.get(0); // 自动类型推导,无需强转
    四、泛型核心语法
  3. 泛型类
    在类名后定义(T为类型形参,任意大写字母:T/E/K/V常用),约束类中成员、方法的类型:
    // 自定义泛型容器类
    public class MyContainer {
    private T data;
    public void setData(T data) { this.data = data; }
    public T getData() { return data; }
    }
    // 使用:指定实际类型String
    MyContainer container = new MyContainer<>();
    container.setData("hello");
  4. 泛型方法
    方法上单独声明泛型,优先级高于类泛型,可用于静态方法(类泛型静态方法不能使用):
    // 声明泛型,返回List
    public static List copyList(List src) {
    List dest = new ArrayList<>();
    dest.addAll(src);
    return dest;
    }
  5. 泛型接口
    // 泛型接口
    public interface IStore {
    void save(T t);
    }
    // 实现类指定具体类型
    class StringStore implements IStore {
    @Override
    public void save(String s) {}
    }
    五、泛型关键特性(集合高频使用)
  6. 类型擦除(本质原理)
    泛型只存在编译期,编译后全部擦除为原生类型(Raw Type):
    • List、List编译后都变成List(原生集合)
    • 字节码层面只保留Object,JVM 不区分泛型类型
    • 因此不能用泛型类型创建数组、不能用instanceof判断泛型
    // 错误:类型擦除后无法区分
    // List[] arr = new List[5];
  7. 通配符 ?(适配任意泛型集合)
    用于方法参数接收任意泛型类型的集合,不能添加元素(类型不确定),只能读取:
    // 可以接收 List、List 等所有List
    public void printAll(List<?> list) {
    for (Object o : list) {
    System.out.println(o);
    }
    // list.add(1); 编译报错,无法确定元素类型
    }
    (1)上界通配符 ? extends T
    只能读取,不能写入,代表T及其子类,常用于读取集合数据:
    // 只能存Number、Integer、Double等Number子类
    public void showNum(List<? extends Number> list) {
    Number num = list.get(0); // 读取没问题
    // list.add(10); 报错,不知道具体子类类型
    }
    (2)下界通配符 ? super T
    只能写入T及子类,读取只能用Object接收,常用于写入集合:
    // 只能存Integer、Integer父类Number/Object
    public void addInt(List<? super Integer> list) {
    list.add(100); // 可写入Integer
    Object o = list.get(0); // 读取只能转Object
    }
  8. 泛型无继承关系
    List 不是 List
posted @ 2026-07-01 20:15  人青是个小卷毛  阅读(12)  评论(0)    收藏  举报