Java集合框架概述

Java集合框架(Java Collections Framework, JCF)是Java标准库中用于存储、操作和聚合数据的一组接口和类。它提供了高效的数据结构和算法,简化了开发过程。

核心接口

Collection接口:所有集合类的根接口,定义了基本操作如添加、删除、遍历等。

List接口概述

List接口是Java集合框架中的核心接口之一,继承自Collection接口,用于表示有序、可重复的元素集合。它允许通过索引(位置)精确控制元素的插入、访问和删除,并提供了丰富的操作方法。

核心特点

  • 有序性:元素按插入顺序存储,可通过索引(如get(int index))访问。
  • 可重复性:允许存储相同值的多个元素。
  • 动态扩容:底层实现类(如ArrayList)自动处理容量调整。
  • ArrayList:基于动态数组,随机访问高效(O(1)),但插入/删除中间元素较慢(O(n))。
  • LinkedList:基于双向链表,插入/删除高效(O(1)),但随机访问较慢(O(n))。
  • Vector:线程安全的动态数组,但性能较低,通常被ArrayList替代。
  • 线程安全ArrayListLinkedList非线程安全,多线程环境下需使用Collections.synchronizedList包装或CopyOnWriteArrayList
  • 性能选择:频繁随机访问选ArrayList,频繁插入/删除选LinkedList
  • 泛型支持:建议使用泛型(如List<String>)避免类型转换错误。

Set接口概述

Set接口是Java集合框架中的一员,继承自Collection接口,用于存储不重复元素的集合。Set不保证元素的顺序(具体实现类可能提供顺序保证,如LinkedHashSet),主要实现类包括HashSetTreeSetLinkedHashSet


Set接口的核心特性

  1. 元素唯一性
    Set中不允许包含重复元素,添加重复元素时会被自动忽略。判断重复的依据是equals()hashCode()方法(对于HashSet)或compareTo()方法(对于TreeSet)。

  2. 无序性(多数实现)
    LinkedHashSetTreeSet外,HashSet等实现不保证元素的存储顺序与插入顺序一致。

  3. 允许null元素
    大多数实现(如HashSet)允许一个null元素,但TreeSet不允许(会抛出NullPointerException)。


常用实现类对比

实现类 底层结构 是否有序 线程安全 允许null 时间复杂度(查询/插入)
HashSet 哈希表 无序 O(1)
LinkedHashSet 哈希表+双向链表 按插入顺序 O(1)
TreeSet 红黑树 自然或定制排序 O(log n)

常用方法示例

Set<String> set = new HashSet<>();
set.add("Apple");      // 添加元素
set.add("Banana");
set.add("Apple");      // 重复元素,添加失败

System.out.println(set.contains("Apple")); // 输出: true
set.remove("Banana");  // 删除元素


适用场景

  • 去重操作:快速过滤重复数据。
  • 集合运算:使用addAll()(并集)、retainAll()(交集)等方法。
  • 快速查找HashSet适合高频查询场景,TreeSet适合需要排序的场景。

注意事项

  1. 重写equals()时必须同时重写hashCode(),确保哈希表正常运作。
  2. TreeSet需实现Comparable接口或提供Comparator,否则抛出ClassCastException
  3. 线程不安全,多线程环境下建议用Collections.synchronizedSet()包装或使用ConcurrentHashMap实现的Set

Queue接口概述

Queue是Java集合框架中的接口,继承自Collection接口,用于表示一种先进先出(FIFO)的数据结构。它定义了队列的基本操作,如插入、删除、检查元素等。Queue通常用于任务调度、缓冲处理等场景。

核心方法

插入操作

  • boolean add(E e): 将元素插入队列,成功返回true,失败时抛出异常(如容量限制)。
  • boolean offer(E e): 尝试插入元素,成功返回true,失败返回false(推荐使用)。

删除操作

  • E remove(): 移除并返回队列头部元素,队列为空时抛出异常。
  • E poll(): 移除并返回队列头部元素,队列为空时返回null(推荐使用)。

检查操作

  • E element(): 返回队列头部元素但不移除,队列为空时抛出异常。
  • E peek(): 返回队列头部元素但不移除,队列为空时返回null(推荐使用)。

实现类

  1. LinkedList
    双向链表实现,支持所有Queue操作,也可作为双端队列使用。

    Queue<String> queue = new LinkedList<>();
    queue.offer("A");
    queue.poll();
    

  2. PriorityQueue
    基于优先级堆的无界队列,元素按自然顺序或自定义Comparator排序。

    Queue<Integer> pq = new PriorityQueue<>();
    pq.offer(3);
    pq.poll(); // 可能返回最小元素
    

  3. ArrayDeque
    基于循环数组的高效双端队列实现,适合频繁插入/删除操作。

阻塞队列(BlockingQueue)

Queue的子接口,支持线程安全的阻塞操作,常见实现:

  • LinkedBlockingQueue: 基于链表的可选容量阻塞队列。
  • ArrayBlockingQueue: 固定大小的数组阻塞队列。
  • PriorityBlockingQueue: 带优先级的无界阻塞队列。

使用示例

Queue<Integer> queue = new LinkedList<>();
queue.offer(10);
queue.offer(20);
System.out.println(queue.poll()); // 输出10
System.out.println(queue.peek()); // 输出20

注意事项

  • 优先使用offerpollpeek等非异常方法。
  • 多线程环境需选择线程安全实现(如ConcurrentLinkedQueueBlockingQueue)。
  • PriorityQueue的迭代顺序不保证按优先级排列,仅poll/peek方法体现优先级。

Map接口概述

Map是Java集合框架中的核心接口之一,用于存储键值对(Key-Value)数据。每个键(Key)对应一个值(Value),键不可重复,值可以重复。Map接口提供了丰富的操作方法,适用于需要通过唯一标识快速查找数据的场景。


主要实现类

  1. HashMap

    • 基于哈希表实现,允许null键和null值。
    • 非线程安全,性能较高。
    • 示例代码:
      Map<String, Integer> map = new HashMap<>();
      map.put("key1", 100);
      Integer value = map.get("key1"); // 返回100
      

  2. LinkedHashMap

    • 继承自HashMap,通过双向链表维护插入顺序或访问顺序。
    • 适合需要有序遍历的场景。
  3. TreeMap

    • 基于红黑树实现,按键的自然顺序或自定义比较器排序。
    • 支持范围查询操作(如subMap())。
  4. Hashtable

    • 线程安全的遗留类,不允许null键和null值。
    • 通常推荐使用ConcurrentHashMap替代。
  5. ConcurrentHashMap

    • 线程安全且高并发优化的实现,分段锁机制提升性能。

核心方法

  • 增删改查

    • put(K key, V value):添加或更新键值对。
    • remove(Object key):删除指定键的映射。
    • get(Object key):获取键对应的值。
    • containsKey(Object key):检查键是否存在。
  • 遍历操作

    • keySet():返回所有键的集合。
    • values():返回所有值的集合。
    • entrySet():返回所有键值对的集合(Map.Entry对象)。
      示例:
      for (Map.Entry<String, Integer> entry : map.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
      }
      

  • 其他方法

    • size():返回键值对数量。
    • clear():清空所有映射。
    • putAll(Map<? extends K, ? extends V> m):批量添加映射。

使用注意事项

  1. 键的唯一性

    • 若键为自定义对象,需重写hashCode()equals()方法以保证唯一性。
  2. 性能选择

    • 高频读写且无需排序:优先选择HashMap
    • 需要排序:使用TreeMap
    • 线程安全场景:选用ConcurrentHashMap
  3. 并发问题

    • 多线程环境下,非线程安全的HashMap可能导致数据不一致,需通过Collections.synchronizedMap包装或直接使用ConcurrentHashMap

示例场景

  1. 统计词频

    Map<String, Integer> frequency = new HashMap<>();
    String[] words = {"apple", "banana", "apple"};
    for (String word : words) {
        frequency.put(word, frequency.getOrDefault(word, 0) + 1);
    }
    // 输出:{apple=2, banana=1}
    

  2. 缓存实现

    Map<String, Object> cache = new LinkedHashMap<>(16, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {
            return size() > 100; // 限制缓存大小
        }
    };
    

并发集合类

Java还提供了线程安全的集合类,位于java.util.concurrent包:

  • ConcurrentHashMap:线程安全的HashMap
  • CopyOnWriteArrayList:写时复制的线程安全List
  • BlockingQueue:支持阻塞操作的队列接口,如ArrayBlockingQueueLinkedBlockingQueue

工具类

  • Collections:提供静态方法用于操作集合(如排序、查找、同步包装等)。
  • Arrays:提供操作数组的工具方法(如转换为集合)。

示例代码片段

// List示例
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");

// Set示例
Set<Integer> hashSet = new HashSet<>();
hashSet.add(1);
hashSet.add(2);

// Map示例
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Key1", 100);
hashMap.put("Key2", 200);

选择集合类的建议

  • 需要快速随机访问:ArrayList
  • 频繁插入删除:LinkedList
  • 去重且不关心顺序:HashSet
  • 需要键值对存储:HashMap
  • 线程安全场景:ConcurrentHashMapCopyOnWriteArrayList

Java集合框架的设计遵循高内聚低耦合原则,通过统一的接口和泛型支持,极大提升了代码的可复用性和类型安全性。

更多推荐