Set接口

因为 Set 集合通常不能记住元素的添加顺序,所以 Set 集合中的元素不按特定的方式进行排序,只是简单地把元素添加到集合中,但 Set 集合中不能包含重复的元素。

Set接口概述

Set 集合由 Set 接口和 Set 接口的实现类组成。Set 接口继承了 Collection 接口,因此它包含了 Collection 接口中的所有方法。Set 接口常用的实现类有 HashSet 类与 TreeSet 类,下面分别对其进行讲解。

Set 集合的构造有一个约束条件,传入的 Collection 对象不能有重复值,必须小心操作可变对象 (mutable object)。如果一个 Set 集合中的可变元素改变了自身状态而导致 Object.equals(Object) = true,则会出现一些问题。

HashSet类

HashSet 类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 Set 集合的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

使用 Set 接口时通常被声明为 Set 类型,通过 HashSet 类可以实例化 Set 接口。代码如下:

Set<E> set = new HashSet<>();

下面通过一个实例来演示 HashSet 类的使用方法。

【例12.4】从入门到精通系列的图书有哪些(实例位置:资源包\TM\sl\12\4)

使用 HashSet 类实例化 Set 接口,向集合中添加 “Java从入门到精通”、“Python从入门到精通”、“C语言从入门到精通”、“C#从入门到精通”,使用 foreach 循环遍历集合中的元素,并把它们输出到控制台上。代码如下:

import java.util.HashSet;
import java.util.Set;

public class IteratorTest {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();  // 定义一个 Set 集合
        String str1 = new String("Java 从入门到精通");
        String str2 = new String("Python 从入门到精通");
        String str3 = new String("C 从入门到精通");
        String str4 = new String("C# 从入门到精通");
        set.add(str1);
        set.add(str2);
        set.add(str3);
        set.add(str4);
        System.out.println("从入门到精通系列的图书有:");
        for(String string : set) {
            String vaule = string;
            System.out.println(vaule);
        }

    }
}

运行结果如下:

     从入门到精通系列的图书有:
     Java从入门到精通
     Python从入门到精通
     C#从入门到精通
     C语言从入门到精通

TreeSet类

通过 TreeSet 类可以实例化 Set 接口。代码如下:

Set<E> set = new TreeSet<>();

TreeSet 类不仅实现了 Set 接口,还实现了 java.util.SortedSet 接口,因此在遍历集合时,TreeSet 类实现的 Set 集合可以按照自然顺序进行递增排序,也可以按照指定比较器进行递增排序,即可以通过比较器对用 TreeSet 类实现的 Set 集合中的对象进行排序。TreeSet 类新增的方法如表12.3所示。

image 2024 03 03 20 15 04 349
Figure 1. 表12.3 TreeSet类增加的方法

下面通过一个实例来演示 TreeSet 类的使用方法。

【例12.5】使用TreeSet类实现自然(升序)排序(实例位置:资源包\TM\sl\12\5)

在项目中创建 TreeSetTest 类,首先使用 TreeSet 类创建一个 Set 集合对象,然后使用 add() 方法向 Set 集合中添加 5 个元素,即 -5、-7、10、6 和 3,最后使用 Iterator 迭代器遍历并输出 Set 集合中的元素。实例代码如下:

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest {  // 创建 TreeSetTest 类
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<>();    // 使用 TreeSet 类创建 Set 集合对象
        set.add(-5);
        set.add(-7);
        set.add(10);
        set.add(6);
        set.add(3);
        Iterator<Integer> it = set.iterator();   // 创建 Iterator 迭代器对象
        System.out.println("Set 集合中的元素的:"); // 提示信息
        while(it.hasNext()) {
            System.out.println(it.next() + " ");
        }
    }
}

运行结果如图12.5所示。

headSet()、subSet()、tailSet() 方法截取对象生成新集合时是否包含指定的参数,可通过如下方法来判别:

  1. 如果指定参数位于新集合的起始位置处,则包含该对象,如 subSet() 方法的第一个参数和 tailSet() 方法的参数。

  2. 如果指定参数是新集合的终止位置处,则不包含该参数,如 headSet() 方法的入口参数和 subSet() 方法的第二个入口参数。

编程训练(答案位置:资源包\TM\sl\12\编程训练)

【训练3】使用TreeSet类排序 使用TreeSet类实现定制排序(降序)(如-5、-7、3、6、10)。

【训练4】模拟当当网购物车 有位读者看中了3本书:《Java从入门到精通》,明日科技编著,59.8元;《Java从入门到精通(实例版)》,明日科技编著,69.8元;《Java Web从入门到精通》,明日科技编著,69.8元。他把这3本书放进了购物车里打算结账:使用封装和HashSet类,输出这3本书的信息,并求出3本书的价格总和,运行结果如图12.6所示。

image 2024 03 03 20 24 21 908
Figure 2. 图12.5 例12.3的运行结果
image 2024 03 03 20 24 45 820
Figure 3. 图12.6 模拟当当网购物车