【Java基础整理】Java集合详解

15 阅读10分钟

Java集合详解

1. 集合概述

Java为了方便对多个对象进行操作,我们可以将多个对象存储到集合中进行对象的操作。

集合类属于工具类,位于java.util包中。

集合的特点

  1. 只存储对象:集合类只用于存储对象,不能存储基本数据类型。

  2. 长度可变:集合长度是可变的,可以动态增加或删除元素。

  3. 类型灵活:一个集合可以存储多个不同类型的对象,但为了避免运行时出现类型不一致异常,JDK1.5后我们可以使用泛型来限定类型。

2. 集合类关系图

image.png

3. 主要集合接口和类

接口层次结构

Collection:单元素集合的顶层接口
├── List:有序集合顶层接口
│   ├── ArrayList:数组数据结构
│   ├── LinkedList:链表数据结构
│   └── Vector:已过时,数组数据结构,线程安全
└── Set:无序集合顶层接口(无重复元素)
    ├── HashSet:根据元素的哈希表来存储元素
    └── TreeSet:树形结构的集合

Map:双元素键值对集合,顶层接口
├── Hashtable:JDK1.2之前就存在,底层是哈希表
├── HashMap:哈希表数据结构
└── TreeMap:二叉树无序集合

Iterator:遍历集合的迭代器(顶层接口)

4. Iterator迭代器接口

Iterator可以迭代获取List、Set集合中的元素。

主要方法

方法名功能描述
hasNext()判断是否有下一个元素
next()返回下一个元素
remove()删除当前元素

扩展:ListIterator

Iterator有个子接口ListIterator,此接口对象在遍历时可以对List集合进行增删改查的操作。

5. Collection接口

Collection是所有集合类的父接口,只要是集合,它必定实现了Collection的方法。

常用方法

方法名功能描述
add()添加元素
addAll()添加一组元素
clear()清空容器
remove()移除一个元素
removeAll()移除一堆元素
contains()判断是否包含某元素
equals()比较某元素
hashCode()返回哈希值
isEmpty()判断是否有元素
size()获取集合长度
retainAll()取交集,集合中只保留与第二个集合交集的元素
toArray()转换成数组
iterator()生产一个迭代器,返回Iterator接口类型的对象

Collection常见的有两个子接口:List和Set,它们的数据存储结构不同。最主要的是List集合是有序的,有索引位置,可以用角标来获取操作元素。

6. List接口详解

List特点

  • 有序集合:具有索引位置的有序元素集合
  • 支持角标操作:具有一系列能使用角标位置操作元素的方法

List特有方法

方法名功能描述
add(int index, E element)在指定位置插入元素
get(int index)获取指定位置的元素
indexOf()获取元素的索引位置
remove(int index)删除指定位置的元素
set(int index, E element)替换指定位置的元素
subList(int fromIndex, int toIndex)获取子列表

List接口实现类

6.1 ArrayList
  • 数据结构:数组
  • 特点:查询快,增删慢
  • 实现:实现了List接口,特有方法不多,方法摘要可参考List接口
6.2 LinkedList
  • 数据结构:链表
  • 特点:查询慢,增删快

LinkedList特有方法:

// 早期方法
addFirst();      // 在开头添加元素
addLast();       // 在末尾添加元素
getFirst();      // 获取第一个元素
getLast();       // 获取最后一个元素
removeFirst();   // 删除第一个元素
removeLast();    // 删除最后一个元素

// JDK 1.6以后的新方法(推荐使用)
offerFirst();    // 在开头添加元素
offerLast();     // 在末尾添加元素
peekFirst();     // 查看第一个元素
peekLast();      // 查看最后一个元素
pollFirst();     // 删除并返回第一个元素
pollLast();      // 删除并返回最后一个元素
6.3 Vector(已过时)
  • 数据结构:数组
  • 特点:线程安全,效率低,已被ArrayList代替
  • 特有方法elements() - 获取Vector的元素,返回枚举类型对象

7. Set接口详解

Set特点

  • 无序集合:没有索引位置
  • 无重复元素:不允许存储重复元素
  • 方法与Collection一致:Set接口没有特有方法,与Collection接口方法一致

Set接口实现类

7.1 HashSet

特点:

  • 底层数据结构:哈希表
  • 无序存入:元素排列方式与存入顺序无关
  • 内部有序:集合内部按照对象的哈希值排列

元素重复判断机制:

  1. 首先比较哈希值
  2. 如果哈希值相等,再调用equals()方法比较对象内容
  3. 如果哈希值不相等,直接判定为不同对象

自定义类在HashSet中的使用示例:

public class Person {
    private String name;
    private int age;
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 重写hashCode方法
    @Override
    public int hashCode() {
        // 返回的哈希值主要依据对象属性信息
        // 尽量避免对象属性值的相同
        return name.hashCode() + age;
    }
    
    // 重写equals方法
    @Override
    public boolean equals(Object obj) {
        // 如果对象不属于Person类型,返回false
        if (!(obj instanceof Person)) {
            return false;
        } else {
            // 将对象强转为Person类型,并比较两个属性
            Person p = (Person) obj;
            return this.name.equals(p.name) && this.age == p.age;
        }
    }
    
    // 此处省略Getters and Setters方法
}
7.2 TreeSet

特点:

  • 底层数据结构:二叉树
  • 存入无序,内部有序:存入时无序,但内部按照自然顺序排序
  • 自动排序:存入元素时会进行自然顺序对比

TreeSet的排序机制

方式一:自然排序(Comparable接口)

原理:

  • Java中的Comparable接口强行对实现它的每个类的对象进行整体排序
  • 此排序被称为该类的自然排序
  • 类的compareTo方法被称为自然比较方法

自定义Student类实现Comparable接口示例:

public class Student implements Comparable {
    private String name;
    private int age;
    
    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 重写compareTo方法
    @Override
    public int compareTo(Object obj) {
        // 如果比较对象不是Student类型,无比较意义
        if (!(obj instanceof Student)) {
            throw new RuntimeException("比较对象不是Student对象");
        }
        
        Student s = (Student) obj;
        
        // 对象按照age的自然顺序来排序
        if (this.age > s.age) {
            return 1;  // 返回正整数代表此对象大于比较对象
        }
        // 如果age值相等,按照name的字符串自然顺序排序
        if (this.age == s.age) {
            return this.name.compareTo(s.name);
        } else {
            return -1;  // 返回负整数代表此对象小于比较对象
        }
    }
    
    // 此处省略Student类变量的Getters and Setters方法
}

⚠️ 注意: compareTo方法返回0时,系统判定比较的两个对象为相同元素,不会将元素存入集合中。

扩展技巧: 如果将compareTo方法的返回值固定为正整数或负整数,TreeSet集合就成了一个链表结构的Set集合。

方式二:比较器排序(Comparator接口)

使用场景:

  • 元素自身不具备比较性,没实现Comparable接口
  • 具备的比较性不是我们所需要的

实现步骤:

  1. 实现Comparator接口
  2. 重写compare(T o1, T o2)方法
  3. 将比较器传入TreeSet的构造方法中

构造方法:

TreeSet(Comparator<? super E> comparator)

定义比较器示例:

// 1. 实现Comparator接口
// 2. 重写compare(T o1, T o2)方法
// 3. 重写equals方法(可选)

8. 两个排序接口对比

接口包位置方法用途
Comparablejava.langcompareTo()强行对类的对象进行自然排序
Comparatorjava.utilcompare()比较函数强行对某些对象集合进行整体排序

元素判重机制:

  • HashSet:根据hashCodeequals方法判断元素是否相同
  • TreeSet:根据compareTo的返回值是否为0判断元素是否相同

9. Map接口详解

Map特点

  • 键值对存储:存储键值对元素
  • 键的唯一性:需要保证键的唯一性
  • 无序集合:没有角标位置
  • 支持键排序:可以使用键的自然顺序排序,并按照键获取值

Map主要方法

方法名功能描述
put(K key, V value)添加键值对,返回原值
putAll(Map<? extends K, ? extends V> m)添加一组键值对
clear()移除所有映射关系
containsKey(Object key)判断是否包含指定键
get(Object key)根据键获取值,若此键无元素返回null
hashCode()返回哈希码值
isEmpty()判断是否为空
equals()判断是否相等
remove(Object key)按照键删除映射关系
size()返回键值对数量
values()获取所有值,返回Collection类型
keySet()返回Set集合,将所有键存入Set集合中
entrySet()返回Map关系集合,Map关系是Map.Entry类型对象

Map.Entry接口

描述: Map中的一个内部接口,表示映射项(键值对)

获取方式: 通过Map中的entrySet()方法获取

主要方法:

方法名功能描述
getKey()获取键
getValue()获取值
setValue(V value)设置值
hashCode()返回哈希码
equals(Object o)判断相等

Map接口实现类

9.1 HashMap
  • 数据结构:哈希表
  • 线程安全:线程不同步
  • 空值支持:允许使用空键或空值
  • 有序性:无序集合,但内部按照键的哈希值排序
9.2 TreeMap
  • 数据结构:二叉树
  • 有序性:无序集合,内部按照键的二叉树结构排序
  • 排序控制:可以改变键的自然顺序来改变集合中元素的顺序
9.3 Hashtable(不推荐)
  • 数据结构:哈希表
  • 线程安全:线程同步
  • 空值支持:不可以存入空键或空值
  • 历史地位:JDK1.2之前存在,现在一般选择HashMap

💡 提示: HashMap和TreeMap最常用的方法是entrySet()

10. Collections工具类

Collections是专门对集合进行操作的工具类,只包含静态方法。

常用方法

方法名功能描述
sort()对集合进行内部排序,一般用于List集合
max()返回最大元素
min()返回最小元素
binarySearch(List list, T key)对List集合进行二分搜索
copy()复制集合
fill(List list, T obj)替换集合中所有元素
replaceAll(List list, T oldVal, T newVal)替换指定元素
reverse(List list)反转集合
reverseOrder()获取逆向比较器,用于反转自然顺序排列
synchronizedCollection(Collection c)给指定集合加锁
swap(List list, int i, int j)交换位置
shuffle()随机交换位置,重新排列集合

11. 容易混淆的类对比

类/接口名类型功能描述
Collection集合接口所有集合的顶层接口
Collections工具类操作集合的工具类,包含静态方法
Comparable排序接口自然排序接口,实现后重写compareTo方法进行排序
Comparator比较器接口比较器接口,包含compareequals方法,构造具有自定义比较器的集合
Collator抽象类Comparator的子类,抽象类

12. 集合选择指南

根据需求选择集合类型

需要保证元素顺序且允许重复:

  • 查询多,增删少 → ArrayList
  • 增删多,查询少 → LinkedList

需要保证元素唯一且不关心顺序:

  • 无排序需求 → HashSet
  • 需要排序 → TreeSet

需要键值对存储:

  • 无排序需求 → HashMap
  • 需要按键排序 → TreeMap

性能对比表

集合类型查询插入删除线程安全
ArrayList
LinkedList
Vector
HashSet
TreeSet较快较慢较慢
HashMap
TreeMap较快较慢较慢
Hashtable

总结

Java集合框架为我们提供了丰富的数据结构选择:

  1. Collection系列:用于存储单个元素

    • List:有序可重复
    • Set:无序不重复
  2. Map系列:用于存储键值对

    • 根据是否需要排序选择HashMap或TreeMap
  3. 选择原则

    • 根据数据特点选择合适的集合类型
    • 考虑线程安全需求
    • 权衡查询和修改操作的频率
  4. 工具支持

    • 使用Collections工具类进行集合操作
    • 合理使用Iterator进行遍历
    • 正确实现hashCode和equals方法

掌握Java集合框架,能够让我们更高效地处理数据,是Java开发的重要基础技能。


本文详细介绍了Java集合框架的核心概念、主要接口和实现类,以及实际使用中的选择策略,希望对Java学习者有所帮助。