Skip to content

第12章_集合框架


12.1 概述


  • 生活中的容器
image-20220523190743146

12.1.1 数组的特点与弊端


  • 为什么有了数组还需要用集合框架???

    • 一方面,面向对象语言对事物的体现都是以 对象 的形式,

      为了方便对多个对象的操作,就要对 对象 进行存储。

    • 另一方面,使用数组存储对象方面具有 一些弊端 ,而 Java 集合就像一种容器,

      可以 动态地 把多个对象的引用放入容器中。


  • 数组在内存存储方面的 特点
    • 数组初始化以后,长度就确定了。
    • 数组中的添加的元素是依次紧密排列的,有序的,可以重复的。
    • 数组声明的类型,就决定了进行元素初始化时的类型。不是此类型的变量,就不能添加。
    • 可以存储基本数据类型值,也可以存储引用数据类型的变量

  • 数组在存储数据方面的 弊端
    • 数组初始化以后,长度就不可变了,不便于扩展
    • 数组中提供的属性和方法少,不便于进行添加、删除、插入、获取元素个数等操作,且效率不高。
    • 数组存储数据的特点单一,只能存储有序的、可以重复的数据

  • Java 集合框架中的类可以用于存储多个 对象 ,还可用于保存具有 映射关系 的关联数组。

12.1.2 java 集合框架体系


  • Java 集合可分为 CollectionMap 两大体系:


    • Collection 接口:用于存储一个一个的数据,也称 单列数据集合
      • List 子接口:用来存储有序的、可以重复的数据(主要用来替换数组,"动态"数组)
        • 实现类:ArrayList (主要实现类) 、LinkedListVector
      • Set 子接口:用来存储无序的、不可重复的数据(类似于高中讲的"集合")
        • 实现类:HashSet (主要实现类) 、LinkedHashSetTreeSet

    • Map 接口:用于存储具有映射关系 “key-value对” 的集合,即一对一对的数据,

      也称 双列数据集合 。(类似于高中的函数、映射。(x1,y1),(x2,y2) ---> y = f(x) )

      • HashMap (主要实现类)、LinkedHashMapTreeMapHashtableProperties

  • JDK 提供的集合 API 位于 java.util 包内

  • 图示:集合框架全图
微信截图_20250706153736
  • 简图1: Collection接口继承树
image-20220407203244029
  • 简图2:Map接口继承树
image-20220407203412665

12.2 Collection 接口及方法


  • JDK 不提供此接口的任何直接实现,而是提供更具体的子接口(如:SetList)去实现。

  • Collection 接口是 ListSet 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,

    也可用于操作 List 集合。方法如下:


12.2.1 添加


  • add(E obj) :添加元素对象到当前集合中
  • addAll(Collection other) :添加 other 集合中的所有元素对象到当前集合中,即 this = this ∪ other

  • 示例:注意 addaddAll 的区别
java
@Test
public void testAdd(){
    //ArrayList是Collection的子接口List的实现类之一。
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    System.out.println(coll);  // [小李广, 扫地僧, 石破天]
}
  
@Test
public void testAddAll(){
    Collection c1 = new ArrayList();
    c1.add(1);
    c1.add(2);
    System.out.println("c1集合元素的个数:" + c1.size()); //c1集合元素的个数:2
    System.out.println("c1 = " + c1); // c1 = [1, 2]

    Collection c2 = new ArrayList();
    c2.add(1);
    c2.add(2);
    System.out.println("c2集合元素的个数:" + c2.size()); //c2集合元素的个数:2
    System.out.println("c2 = " + c2); // c2 = [1, 2]

    Collection other = new ArrayList();
    other.add(1);
    other.add(2);
    other.add(3);
    System.out.println("other集合元素的个数:" + other.size()); // other集合元素的个数:3
    System.out.println("other = " + other); // other = [1, 2, 3]
    System.out.println();

    c1.addAll(other);
    System.out.println("c1集合元素的个数:" + c1.size()); // c1集合元素的个数:5
    System.out.println("c1.addAll(other) = " + c1); // c1.addAll(other) = [1, 2, 1, 2, 3]

    c2.add(other);
    System.out.println("c2集合元素的个数:" + c2.size()); // c2集合元素的个数:3
    System.out.println("c2.add(other) = " + c2); // c2.add(other) = [1, 2, [1, 2, 3]]
}

图示: coll.addAll(other);coll.add(other);

1563548078274

12.2.2 判断


  • int size():获取当前集合中实际存储的元素个数

  • boolean isEmpty():判断当前集合是否为空集合

  • boolean contains(Object obj):判断当前集合中是否存在一个与 obj 对象 equals 返回 true 的元素

  • boolean containsAll(Collection coll):判断 coll 集合中的元素是否在当前集合中都存在。

    换言之 : coll 集合是否是当前集合的 “子集”

  • boolean equals(Object obj):判断当前集合与 obj 是否相等


  • 示例:
java
@Test
public void test01() {
    Collection coll = new ArrayList();
    System.out.println("coll在添加元素之前,isEmpty = " + coll.isEmpty()); // coll在添加元素之前,isEmpty = true
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    coll.add("佛地魔");
    System.out.println("coll的元素个数" + coll.size()); // coll的元素个数4
    System.out.println("coll在添加元素之后,isEmpty = " + coll.isEmpty()); // coll在添加元素之后,isEmpty = false
}

@Test
public void test02() {
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    coll.add("佛地魔");
    System.out.println("coll = " + coll); // coll = [小李广, 扫地僧, 石破天, 佛地魔]
    System.out.println("coll是否包含“小李广” = " + coll.contains("小李广")); // coll是否包含“小李广” = true
    System.out.println("coll是否包含“宋红康” = " + coll.contains("宋红康")); // coll是否包含“宋红康” = false

    Collection other = new ArrayList();
    other.add("小李广");
    other.add("扫地僧");
    other.add("尚硅谷");
    System.out.println("other = " + other); // other = [小李广, 扫地僧, 尚硅谷]
    System.out.println("coll.containsAll(other) = " + coll.containsAll(other)); // coll.containsAll(other) = false
}

@Test
public void test03(){
    Collection c1 = new ArrayList();
    c1.add(1);
    c1.add(2);
    System.out.println("c1集合元素的个数:" + c1.size()); // c1集合元素的个数:2
    System.out.println("c1 = " + c1); // c1 = [1, 2]

    Collection c2 = new ArrayList();
    c2.add(1);
    c2.add(2);
    System.out.println("c2集合元素的个数:" + c2.size()); // c2集合元素的个数:2
    System.out.println("c2 = " + c2); // c2 = [1, 2]

    Collection other = new ArrayList();
    other.add(1);
    other.add(2);
    other.add(3);
    System.out.println("other集合元素的个数:" + other.size()); // other集合元素的个数:3
    System.out.println("other = " + other); // other = [1, 2, 3]
    System.out.println();

    c1.addAll(other);
    System.out.println("c1集合元素的个数:" + c1.size()); // c1集合元素的个数:5
    System.out.println("c1.addAll(other) = " + c1);  // c1.addAll(other) = [1, 2, 1, 2, 3]
    System.out.println("c1.contains(other) = " + c1.contains(other)); // c1.contains(other) = false
    System.out.println("c1.containsAll(other) = " + c1.containsAll(other)); // c1.containsAll(other) = true
    System.out.println();

    c2.add(other);
    System.out.println("c2集合元素的个数:" + c2.size()); // c2集合元素的个数:3
    System.out.println("c2.add(other) = " + c2); // c2.add(other) = [1, 2, [1, 2, 3]]
    System.out.println("c2.contains(other) = " + c2.contains(other)); // c2.contains(other) = true
    System.out.println("c2.containsAll(other) = " + c2.containsAll(other)); // c2.containsAll(other) = false
}

12.2.3 删除


  • void clear():清空集合元素

  • boolean remove(Object obj) :从当前集合中删除第一个找到的与 obj 对象 equals 返回 true 的元素。

  • boolean removeAll(Collection coll):从当前集合中删除所有与 coll 集合中相同的元素。

    this = this - this ∩ coll

  • boolean retainAll(Collection coll):从当前集合中删除两个集合中不同的元素,使得当前集合

    仅保留与 coll 集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即 this = this ∩ coll


  • 示例:注意几种删除方法的区别
java
@Test
public void testRemove(){
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    coll.add("佛地魔");
    System.out.println("coll = " + coll); // coll = [小李广, 扫地僧, 石破天, 佛地魔]

    coll.remove("小李广");
    System.out.println("删除元素\"小李广\"之后coll = " + coll); // 删除元素"小李广"之后coll = [扫地僧, 石破天, 佛地魔]

    coll.clear();
    System.out.println("coll清空之后,coll = " + coll); // coll清空之后,coll = []
}

@Test
public void testRemoveAll() {
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    coll.add("佛地魔");
    System.out.println("coll = " + coll);  // coll = [小李广, 扫地僧, 石破天, 佛地魔]

    Collection other = new ArrayList();
    other.add("小李广");
    other.add("扫地僧");
    other.add("尚硅谷");
    System.out.println("other = " + other);  // other = [小李广, 扫地僧, 尚硅谷]

    coll.removeAll(other);
    System.out.println("coll.removeAll(other)之后,coll = " + coll);  // coll.removeAll(other)之后,coll = [石破天, 佛地魔]
    System.out.println("coll.removeAll(other)之后,other = " + other);  // coll.removeAll(other)之后,other = [小李广, 扫地僧, 尚硅谷]
}

@Test
public void testRetainAll() {
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    coll.add("佛地魔");
    System.out.println("coll = " + coll); // coll = [小李广, 扫地僧, 石破天, 佛地魔]

    Collection other = new ArrayList();
    other.add("小李广");
    other.add("扫地僧");
    other.add("尚硅谷");
    System.out.println("other = " + other); // other = [小李广, 扫地僧, 尚硅谷]

    coll.retainAll(other);
    System.out.println("coll.retainAll(other)之后,coll = " + coll);  // coll.retainAll(other)之后,coll = [小李广, 扫地僧]
    System.out.println("coll.retainAll(other)之后,other = " + other); // coll.retainAll(other)之后,other = [小李广, 扫地僧, 尚硅谷]
}

12.2.4 其它


  • Object[] toArray() :返回包含当前集合中所有元素的数组
  • hashCode() :获取集合对象的哈希值
  • iterator() :返回迭代器对象,用于集合遍历

  • 示例:
java
@Test
public void testElse() {
    Collection coll = new ArrayList();

    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");
    coll.add("佛地魔");
    //集合转换为数组:集合的toArray()方法
    Object[] objects = coll.toArray();
    System.out.println("用数组返回coll中所有元素:" + Arrays.toString(objects)); 
    // 用数组返回coll中所有元素:[小李广, 扫地僧, 石破天, 佛地魔]

    //对应的,数组转换为集合:调用Arrays的asList(Object ...objs)
    Object[] arr1 = new Object[]{123,"AA","CC"};
    Collection list = Arrays.asList(arr1);
    System.out.println(list); // [123, AA, CC]
}

iterator() 在下面演示 ...


12.3 Iterator(迭代器)接口


12.3.1 Iterator 接口


  • 在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,

    JDK 专门提供了一个接口 java.util.IteratorIterator 接口也是 Java 集合中的一员,

    但它与 CollectionMap 接口有所不同。

    • Collection 接口与 Map 接口主要用于 存储 元素
    • Iterator ,被称为迭代器接口,本身并不提供存储对象的能力,主要用于 遍历 Collection 中的元素

  • Collection 接口继承了 java.lang.Iterable 接口,该接口有一个 iterator() 方法,那么所有实现了

    Collection 接口的集合类都有一个 iterator() 方法,用以返回一个实现了 Iterator 接口的对象。

    • public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的。

    • 集合对象每次调用 iterator() 方法都得到一个全新的迭代器对象,

      默认游标都在集合的第一个元素之前。


  • Iterator 接口的常用方法如下:

    • public E next() : 返回迭代的下一个元素。
    • public boolean hasNext() : 如果仍有元素可以迭代,则返回 true。
  • 注意:在调用 it.next() 方法之前必须要调用 it.hasNext() 进行检测。

    若不调用,且下一条记录无效,直接调用 it.next() 会抛出 NoSuchElementException异常


  • 举例:
java
@Test
public void testNext(){
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");

    Iterator iterator = coll.iterator();
    System.out.println(iterator.next()); // 小李广
    System.out.println(iterator.next()); // 扫地僧
    System.out.println(iterator.next()); // 石破天
    //System.out.println(iterator.next()); //报 NoSuchElementException 异常
}

@Test
public void testHasNext(){
    Collection coll = new ArrayList();
    coll.add("小李广");
    coll.add("扫地僧");
    coll.add("石破天");

    Iterator iterator = coll.iterator();//获取迭代器对象
    while(iterator.hasNext()) {//判断是否还有元素可迭代
        System.out.println(iterator.next());//取出下一个元素
    }
}

12.3.2 迭代器执行原理


  • Iterator 迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,

    接下来通过一个图例来演示 Iterator 对象迭代元素的过程:

image-20220407235130988

另外:使用 Iterator 迭代器删除元素:java.util.Iterator 迭代器中有一个方法:void remove() ;

java
Iterator iter = coll.iterator();//回到起点
while(iter.hasNext()){
    Object obj = iter.next();
    if(obj.equals("Tom")){
        iter.remove();
    }
}
  • 注意:

    • Iterator 可以删除集合的元素,但是遍历过程中通过迭代器对象的 remove 方法,

      不是集合对象的 remove 方法。

    • 如果还未调用 next() 或在上一次调用 next() 方法之后已经调用了 remove() 方法,

      再调用 remove() 都会报 IllegalStateException

    • Collection 已经有 remove(xx) 方法了,为什么 Iterator 迭代器还要提供删除方法呢?

      因为迭代器的 remove() 可以按指定的条件进行删除。


  • 例如:要删除以下集合元素中的偶数
java
@Test
public void testRemoveEven(){
    Collection coll = new ArrayList();
    coll.add(1);
    coll.add(2);
    coll.add(3);
    coll.add(4);
    coll.add(5);
    coll.add(6);

    Iterator iterator = coll.iterator();
    while(iterator.hasNext()){
        Integer element = (Integer) iterator.next();
        if(element % 2 == 0){
            iterator.remove();
        }
    }
    System.out.println(coll);  // [1, 3, 5]
}

JDK8.0 时,Collection 接口有了removeIf 方法,即可以根据条件删除。(第18章中再讲)


12.3.3 foreach 循环


  • foreach 循环(也称增强for循环)是 JDK5.0 中定义的一个高级 for 循环,

    专门用来 遍历数组和集合 的。

  • foreach 循环的语法格式:

java
for(元素的数据类型 局部变量 : Collection 集合或数组){ 
  	//操作局部变量的输出操作
}
//这里局部变量就是一个临时变量,自己命名就可以

12.4 Collection子接口1:List


12.4.1 List 接口特点


  • 鉴于 Java 中数组用来存储数据的局限性,我们通常使用 java.util.List 替代数组

  • List 集合类中 元素有序 、且 可重复 ,集合中的每个元素都有其对应的顺序索引。

    • 举例:List 集合存储数据,就像银行门口客服,给每一个来办理业务的客户分配序号:

      第一个来的是“张三”,客服给他分配的是0;第二个来的是“李四”,客服给他分配的1;

      以此类推,最后一个序号应该是 “总人数-1” 。

    1563549818689
  • JDK API 中 List 接口的实现类常用的有:ArrayListLinkedListVector


12.4.2 List 接口方法


List 除了从 Collection 集合继承的方法外,List 集合里添加了一些 根据索引 来操作集合元素的方法。

  • 插入元素

    • void add(int index, Object ele) : 在 index 位置插入 ele 元素

    • boolean addAll(int index, Collection eles) :从 index 位置开始

      eles 中的所有元素遍历地添加进来

  • 获取元素

    • Object get(int index) : 获取指定 index 位置的元素
    • List subList(int fromIndex, int toIndex) : 返回从 fromIndextoIndex 位置的子集合
  • 获取元素索引

    • int indexOf(Object obj) : 返回 obj 在集合中首次出现的位置
    • int lastIndexOf(Object obj) : 返回 obj 在当前集合中末次出现的位置
  • 删除和替换元素

    • Object remove(int index) : 移除指定 index 位置的元素,并返回此元素
    • Object set(int index, Object ele) : 设置指定 index 位置的元素为 ele