Java集合框架详解

Java集合框架是Java编程中最常用的API之一,本文将全面深入地讲解集合框架的核心概念、常用实现类、使用场景以及最佳实践。

1. 集合框架概述

1.1 什么是集合框架?

Java集合框架(Java Collections Framework)是一组用于存储和操作对象组的数据结构和算法的统一架构。它提供了丰富的数据结构实现,如列表(List)、集合(Set)、队列(Queue)和映射(Map)等。

集合框架的主要优点

  • 提高代码复用性:提供了标准化的数据结构和算法
  • 提高代码质量:经过严格测试,性能优异
  • 降低学习成本:统一的API设计,学习一次即可掌握多种数据结构
  • 提高开发效率:开箱即用,无需从零实现

1.2 集合框架核心接口

Java集合框架的核心接口结构如下:

复制代码
Collection(集合根接口)
├── List(有序、可重复)
│   ├── ArrayList(数组实现)
│   ├── LinkedList(链表实现)
│   └── Vector(线程安全的数组实现)
└── Set(无序、不可重复)
    ├── HashSet(哈希表实现)
    ├── LinkedHashSet(链表+哈希表,有序)
    └── TreeSet(红黑树实现,有序)

Map(键值对根接口)
├── HashMap(哈希表实现)
├── LinkedHashMap(链表+哈希表,有序)
├── TreeMap(红黑树实现,有序)
└── Hashtable(线程安全的哈希表)

2. Collection接口详解

2.1 Collection接口概述

Collection是集合框架的根接口,定义了集合的基本操作方法:

java 复制代码
public interface Collection<E> extends Iterable<E> {
    // 基本操作
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    boolean add(E e);
    boolean remove(Object o);
    
    // 批量操作
    boolean addAll(Collection<? extends E> c);
    boolean containsAll(Collection<?> c);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    void clear();
    
    // 数组转换
    Object[] toArray();
    <T> T[] toArray(T[] a);
    
    // 迭代器
    Iterator<E> iterator();
}

2.2 遍历集合的四种方式

java 复制代码
import java.util.*;

public class CollectionTraversal {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        list.add("JavaScript");
        
        // 方式1:for循环(仅List)
        System.out.println("=== 方式1:for循环 ===");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        
        // 方式2:增强for循环
        System.out.println("\n=== 方式2:增强for循环 ===");
        for (String language : list) {
            System.out.println(language);
        }
        
        // 方式3:Iterator迭代器
        System.out.println("\n=== 方式3:Iterator迭代器 ===");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String lang = iterator.next();
            System.out.println(lang);
        }
        
        // 方式4:Java 8+ forEach
        System.out.println("\n=== 方式4:forEach ===");
        list.forEach(System.out::println);
    }
}

3. List接口详解

3.1 ArrayList详解

ArrayList是最常用的List实现类,基于动态数组实现。

特点

  • 随机访问效率高(O(1))
  • 尾部插入删除效率高(均摊O(1))
  • 中间插入删除效率低(O(n))
  • 线程不安全
java 复制代码
import java.util.*;

public class ArrayListDemo {
    public static void main(String[] args) {
        // 创建ArrayList
        ArrayList<String> arrayList = new ArrayList<>();
        
        // 添加元素
        arrayList.add("Java");
        arrayList.add("Python");
        arrayList.add("C++");
        arrayList.add("JavaScript");
        System.out.println("初始大小: " + arrayList.size());  // 4
        
        // 指定位置插入
        arrayList.add(2, "Go");
        System.out.println("插入后: " + arrayList);  // [Java, Python, Go, C++, JavaScript]
        
        // 获取元素
        String first = arrayList.get(0);
        System.out.println("第一个元素: " + first);  // Java
        
        // 删除元素
        arrayList.remove("C++");
        arrayList.remove(0);  // 按索引删除
        
        // 查找元素
        int index = arrayList.indexOf("Python");
        boolean contains = arrayList.contains("Java");
        
        // 转换为数组
        String[] array = arrayList.toArray(new String[0]);
        
        // 批量操作
        List<String> anotherList = Arrays.asList("Ruby", "PHP");
        arrayList.addAll(anotherList);
        
        // 清空
        arrayList.clear();
    }
}

3.2 LinkedList详解

LinkedList基于双向链表实现,同时实现了List和Deque接口。

特点

  • 插入删除效率高(O(1))
  • 随机访问效率低(O(n))
  • 线程不安全
  • 可作为队列、栈、双端队列使用
java 复制代码
import java.util.*;

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        
        // 作为List使用
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        
        // 作为栈使用(后进先出)
        linkedList.push(0);  // 添加到头部
        linkedList.pop();     // 从头部删除并返回
        
        // 作为队列使用(先进先出)
        linkedList.offer(4);  // 添加到尾部
        linkedList.poll();     // 从头部删除
        
        // 双端队列操作
        linkedList.addFirst(-1);
        linkedList.addLast(100);
        linkedList.removeFirst();
        linkedList.removeLast();
        
        // 获取但不移除
        System.out.println("第一个元素: " + linkedList.getFirst());
        System.out.println("最后一个元素: " + linkedList.getLast());
        
        System.out.println("LinkedList: " + linkedList);
    }
}

3.3 ArrayList vs LinkedList 选择

场景 推荐使用 原因
随机访问多 ArrayList 随机访问O(1)
插入删除多 LinkedList 插入删除O(1)
内存敏感 ArrayList 内存开销小
需要栈/队列 LinkedList 提供了相关方法

4. Set接口详解

4.1 HashSet详解

HashSet是最常用的Set实现类,基于哈希表实现。

特点

  • 元素不可重复
  • 可以存储null
  • 不保证顺序(无序)
  • 线程不安全
  • 增删改查均为O(1)
java 复制代码
import java.util.*;

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet<String> hashSet = new HashSet<>();
        
        // 添加元素
        hashSet.add("Java");
        hashSet.add("Python");
        hashSet.add("C++");
        hashSet.add("Java");  // 重复元素,不会添加
        hashSet.add(null);     // 可以存储null
        
        System.out.println("HashSet大小: " + hashSet.size());  // 4
        System.out.println("HashSet内容: " + hashSet);  // [null, Java, Python, C++](无序)
        
        // 查找元素
        boolean contains = hashSet.contains("Java");  // true
        
        // 删除元素
        hashSet.remove("C++");
        
        // HashSet的去重原理:使用hashCode()和equals()方法
    }
}

4.2 LinkedHashSet详解

LinkedHashSet是HashSet的子类,在哈希表基础上增加了双向链表来维护顺序。

特点

  • 元素不可重复
  • 保持插入顺序
  • 性能略低于HashSet
java 复制代码
import java.util.*;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        
        linkedHashSet.add("Java");
        linkedHashSet.add("Python");
        linkedHashSet.add("C++");
        linkedHashSet.add("Java");  // 重复元素,不会添加
        
        System.out.println("LinkedHashSet(保持插入顺序): " + linkedHashSet);
        // 输出: [Java, Python, C++]
        
        // 应用场景:需要去重且保持顺序
        List<String> listWithDuplicates = Arrays.asList("A", "B", "A", "C", "B", "D");
        LinkedHashSet<String> uniqueOrdered = new LinkedHashSet<>(listWithDuplicates);
        
        System.out.println("去重后的顺序: " + uniqueOrdered);  // [A, B, C, D]
    }
}

4.3 TreeSet详解

TreeSet基于红黑树实现,可以对元素进行排序。

特点

  • 元素不可重复
  • 可以排序(自然排序或自定义Comparator)
  • 增删改查均为O(log n)
  • 不允许存储null
java 复制代码
import java.util.*;

public class TreeSetDemo {
    public static void main(String[] args) {
        // 自然排序(String实现了Comparable接口)
        TreeSet<String> treeSet = new TreeSet<>();
        treeSet.add("Java");
        treeSet.add("Python");
        treeSet.add("C++");
        treeSet.add("Go");
        
        System.out.println("TreeSet(自然排序): " + treeSet);
        // 输出: [C++, Go, Java, Python](按字母顺序)
        
        // TreeSet特有方法
        System.out.println("第一个元素: " + treeSet.first());  // C++
        System.out.println("最后一个元素: " + treeSet.last());  // Python
        System.out.println("小于Python的元素: " + treeSet.headSet("Python"));
        System.out.println("大于等于Java的元素: " + treeSet.tailSet("Java"));
    }
}

5. Map接口详解

5.1 HashMap详解

HashMap是最常用的Map实现类,基于哈希表实现。

特点

  • 键值对存储
  • 键不可重复,值可以重复
  • 允许存储null键和null值
  • 线程不安全
  • 增删改查均为O(1)
java 复制代码
import java.util.*;

public class HashMapDemo {
    public static void main(String[] args) {
        HashMap<String, Integer> hashMap = new HashMap<>();
        
        // 添加键值对
        hashMap.put("Java", 1);
        hashMap.put("Python", 2);
        hashMap.put("C++", 3);
        hashMap.put("Java", 4);  // 键重复,值覆盖
        
        System.out.println("HashMap内容: " + hashMap);
        
        // 获取值
        Integer javaValue = hashMap.get("Java");  // 4
        Integer unknown = hashMap.get("Unknown");  // null
        
        // 获取默认值
        Integer defaultValue = hashMap.getOrDefault("Unknown", 0);  // 0
        
        // 遍历HashMap
        hashMap.forEach((k, v) -> System.out.println(k + " = " + v));
        
        // 删除键值对
        hashMap.remove("C++");
    }
}

5.2 HashMap的底层原理

HashMap的重要常量

  • 默认初始容量:16
  • 负载因子:0.75
  • 当容量使用率达到75%时,会进行扩容(容量翻倍)

添加元素的过程

  1. 计算key的hash值
  2. 根据hash值计算在数组中的索引位置
  3. 如果该位置为空,直接放入
  4. 如果该位置不为空(发生哈希冲突):
    • 如果key相等(hash相同且equals为true),覆盖value
    • 如果key不等,形成链表或红黑树(Java 8+)

5.3 LinkedHashMap详解

LinkedHashMap是HashMap的子类,在哈希表基础上增加了双向链表来维护顺序。

特点

  • 键值对存储
  • 保持插入顺序或访问顺序
  • 性能略低于HashMap
java 复制代码
import java.util.*;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        // 插入顺序
        LinkedHashMap<String, Integer> insertOrderMap = new LinkedHashMap<>();
        insertOrderMap.put("Java", 1);
        insertOrderMap.put("Python", 2);
        insertOrderMap.put("C++", 3);
        
        System.out.println("插入顺序: " + insertOrderMap);
        // 输出: {Java=1, Python=2, C++=3}
        
        // 访问顺序(LRU缓存常用)
        LinkedHashMap<String, Integer> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);
        accessOrderMap.put("Java", 1);
        accessOrderMap.put("Python", 2);
        accessOrderMap.put("C++", 3);
        accessOrderMap.get("Java");  // 访问Java,移到末尾
        
        System.out.println("访问顺序: " + accessOrderMap);
        
        // LRU缓存示例
        LinkedHashMap<String, Integer> lruCache = new LinkedHashMap<>(3) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > 3;
            }
        };
        
        lruCache.put("A", 1);
        lruCache.put("B", 2);
        lruCache.put("C", 3);
        lruCache.put("D", 4);  // 自动删除最老的A
        
        System.out.println("LRU缓存: " + lruCache);
        // 输出: {B=2, C=3, D=4}
    }
}

5.4 TreeMap详解

TreeMap基于红黑树实现,可以对键进行排序。

特点

  • 键值对存储
  • 键不可重复
  • 可以排序(自然排序或自定义Comparator)
  • 增删改查均为O(log n)
java 复制代码
import java.util.*;

public class TreeMapDemo {
    public static void main(String[] args) {
        TreeMap<String, Integer> treeMap = new TreeMap<>();
        treeMap.put("Java", 1);
        treeMap.put("Python", 2);
        treeMap.put("C++", 3);
        
        System.out.println("TreeMap(自然排序): " + treeMap);
        // 输出: {C++=3, Java=1, Python=2}
        
        // TreeMap特有方法
        System.out.println("第一个键: " + treeMap.firstKey());  // C++
        System.out.println("最后一个键: " + treeMap.lastKey());  // Python
        System.out.println("小于Python的键: " + treeMap.headMap("Python"));
        System.out.println("大于等于Java的键: " + treeMap.tailMap("Java"));
    }
}

6. 集合工具类Collections

6.1 排序和查找操作

java 复制代码
import java.util.*;

public class CollectionsDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        
        // 排序
        Collections.sort(list);
        System.out.println("排序后: " + list);
        
        Collections.reverse(list);
        System.out.println("反转后: " + list);
        
        Collections.shuffle(list);
        System.out.println("打乱后: " + list);
        
        // 查找
        Collections.sort(list);
        int index = Collections.binarySearch(list, "Python");
        System.out.println("Python的索引: " + index);
        
        // 最大值/最小值
        System.out.println("最大值: " + Collections.max(list));
        System.out.println("最小值: " + Collections.min(list));
    }
}

6.2 同步控制和不可修改集合

java 复制代码
import java.util.*;

public class CollectionsSync {
    public static void main(String[] args) {
        // 同步集合
        List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
        Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
        Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
        
        // 不可修改集合
        List<String> unmodifiableList = Collections.unmodifiableList(Arrays.asList("A", "B", "C"));
        
        // 单例集合
        List<String> singletonList = Collections.singletonList("唯一元素");
        Set<String> singletonSet = Collections.singleton("唯一元素");
        Map<String, Integer> singletonMap = Collections.singletonMap("key", 1);
        
        // 空集合
        List<String> emptyList = Collections.emptyList();
        Set<String> emptySet = Collections.emptySet();
        Map<String, Integer> emptyMap = Collections.emptyMap();
    }
}

7. 集合最佳实践

7.1 选择正确的集合类型

java 复制代码
public class ChooseRightCollection {
    public static void main(String[] args) {
        // 需要根据索引快速访问元素 → ArrayList
        List<String> list = new ArrayList<>();
        
        // 需要在中间频繁插入/删除 → LinkedList
        List<String> linkedList = new LinkedList<>();
        
        // 需要去重 → HashSet
        Set<String> set = new HashSet<>();
        
        // 需要保持顺序 → LinkedHashSet
        Set<String> orderedSet = new LinkedHashSet<>();
        
        // 需要排序 → TreeSet
        Set<String> sortedSet = new TreeSet<>();
        
        // 需要键值对 → HashMap
        Map<String, Integer> map = new HashMap<>();
        
        // 需要LRU缓存 → LinkedHashMap
        Map<String, Integer> lruCache = new LinkedHashMap<>(3) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > 3;
            }
        };
    }
}

7.2 避免常见错误

java 复制代码
import java.util.*;

public class CollectionMistakes {
    public static void main(String[] args) {
        // 错误1:在循环中删除元素(正确方式)
        List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "B", "D"));
        
        // 正确方式1:使用Iterator
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            if ("B".equals(iterator.next())) {
                iterator.remove();
            }
        }
        
        // 正确方式2:使用removeIf(Java 8+)
        list = new ArrayList<>(Arrays.asList("A", "B", "C", "B", "D"));
        list.removeIf("B"::equals);
        
        // 错误2:修改作为key的对象
        // 避免修改HashMap/HashSet中作为key的对象的hashCode
        
        // 错误3:集合与数组混淆
        String[] array = new String[]{"A", "B", "C"};
        List<String> listFromArray = Arrays.asList(array);  // 固定大小
        List<String> mutableList = new ArrayList<>(Arrays.asList(array));  // 可变大小
    }
}

7.3 性能优化技巧

java 复制代码
public class CollectionPerformance {
    public static void main(String[] args) {
        // 技巧1:指定初始容量(减少扩容次数)
        ArrayList<String> list = new ArrayList<>(1000);
        HashMap<String, Integer> map = new HashMap<>(1000, 0.8f);
        
        // 技巧2:使用接口类型声明
        List<String> list = new ArrayList<>();  // 推荐
        Map<String, Integer> map = new HashMap<>();  // 推荐
        
        // 技巧3:批量操作比循环操作高效
        List<String> list1 = new ArrayList<>(Arrays.asList("A", "B"));
        List<String> list2 = new ArrayList<>(Arrays.asList("C", "D"));
        list1.addAll(list2);  // 高效
        
        // 技巧4:使用正确的数据结构
        Set<String> set = new HashSet<>();  // O(1)contains
        // 不要在List中频繁使用contains(O(n))
    }
}

8. 总结

核心要点回顾

  1. List:有序、可重复

    • ArrayList:随机访问多
    • LinkedList:插入删除多
  2. Set:无序、不可重复

    • HashSet:通用场景
    • LinkedHashSet:保持顺序
    • TreeSet:需要排序
  3. Map:键值对

    • HashMap:通用场景
    • LinkedHashMap:保持顺序/LRU
    • TreeMap:需要排序键
相关推荐
看我干嘛!2 小时前
python第四次作业
开发语言·python
多多*2 小时前
2026年最新 测试开发工程师相关 Linux相关知识点
java·开发语言·javascript·算法·spring·java-ee·maven
树码小子2 小时前
SpringIoC & DI (1):IOC介绍 & Spring IoC使用 & DI
java·后端·spring
tb_first2 小时前
万字超详细苍穹外卖学习笔记5
java·数据库·spring boot·笔记·学习·spring
铁蛋AI编程实战2 小时前
ChatWiki 开源 AI 文档助手搭建教程:多格式文档接入,打造专属知识库机器人
java·人工智能·python·开源
2301_763472582 小时前
实时系统下的C++编程
开发语言·c++·算法
Hx_Ma162 小时前
SpringBoot消息转换器扩展fastjson
java·spring boot·spring
Coder_preston2 小时前
Spring/Spring Boot实战:从入门到项目部署
java·spring boot·spring
山岚的运维笔记2 小时前
SQL Server笔记 -- 第16章:MERGE
java·笔记·sql·microsoft·sqlserver