`

「译」Java集合框架系列教程四:Set接口

    博客分类:
  • Java
 
阅读更多

原文:The Set Interface

译文:Java集合框架系列教程四:Set接口

一个Set是一个不能包含重复元素的集合。它映射了数学意义上的集合抽象。Set接口只是在继承自Collecton接口的方法基础之上加上不允许元素重复的限制。Set也对equals和hashCode的行为规约施加了更强的限制,使得Set实例允许进行有意义的比较,即使他们的具体实现不同。两个集合实例相等(equal)如果它们包含相同的元素。

一个Set是一个不能包含重复元素的集合。它映射了数学意义上的集合抽象。Set接口只是在继承自Collecton接口的方法基础之上加上不允许元素重复的限制。Set也对equals和hashCode的行为规约施加了更强的限制,使得Set实例允许进行有意义的比较,即使他们的具体实现不同。两个集合实例相等(equal)如果它们包含相同的元素。

下面是Set接口的API实现:

public interface Set<E> extends Collection<E> {
    // Basic operations
    int size();
    boolean isEmpty();
    boolean contains(Object element);
    // optional
    boolean add(E element);
    // optional
    boolean remove(Object element);
    Iterator<E> iterator();

    // Bulk operations
    boolean containsAll(Collection<?> c);
    // optional
    boolean addAll(Collection<? extends E> c);
    // optional
    boolean removeAll(Collection<?> c);
    // optional
    boolean retainAll(Collection<?> c);
    // optional
    void clear();

    // Array Operations
    Object[] toArray();
    <T> T[] toArray(T[] a);
}

Java平台提供了通用的Set实现:HashSet、TreeSet和LinkedHashSet。HashSet将元素存储在哈希表(hash table)中,它是最高效的Set实现,但是它无法确定迭代顺序。TreeSet将元素存储在红黑树中,元素按照值进行排序,它比HashSet稍慢。LinkedHashSet是HashSet的链表实现,它保持元素插入的顺序,但是访问性能比HashSet和TreeSet差。

这里有一个简单但是有用的Set使用场景。假设你有一个Collection c,你想创建另外一个Collection,但必须去除重复元素(只保留一个)。下面一行代码就实现了你的要求:

Collection<Type> noDups = new HashSet<Type>(c);

这里有另外一个变种实现,能保证原始集合中元素的顺序:

Collection<Type> noDups = new LinkedHashSet<Type>(c);

下面是一个泛化的封装了上面这行代码的方法:

public static <E> Set<E> removeDups(Collection<E> c) {
   return new LinkedHashSet<E>(c);
}


Set接口的基本操作

size方法返回Set中元素的数目。isEmpty方法判断Set是否为空。add方法往Set中添加指定元素,如果该元素不存在于集合中,并且返回一个布尔值标识元素是否成功添加。类似地,remove方法从Set中移除指定元素,如果该元素存在于集合中,并且返回一个布尔值标识是否成功移除。iterator方法返回Set的迭代器。

下面的程序接受一组单词作为参数args,打印出任何重复的单词、所有不重复单词的数目以及不重复单词列表。

import java.util.*;

public class FindDups {
    public static void main(String[] args) {
        Set<String> s = new HashSet<String>();
        for (String a : args)
            if (!s.add(a))
                System.out.println("Duplicate detected: " + a);

        System.out.println(s.size() + " distinct words: " + s);
    }
}

现在用下面的命令运行程序:

java FindDups i came i saw i left

程序输出如下:

Duplicate detected: i
Duplicate detected: i
4 distinct words: [i, left, saw, came]

注意上面的代码始终通过接口类型(Set)来引用对应的集合,而不是引用具体实现类型(HashSet)。这是强烈推荐使用的编程实践,因为这使得我们能更灵活地切换集合具体实现,只需要改变构造器函数。如果用来存储集合的变量或者用来传递给其他方法的参数被声明为集合具体实现类型而不是集合接口类型,那么这些变量或参数也必须随着具体实现的改变而改变。

前面例子中Set的具体实现类型是HashSet,它不能保证Set中元素的顺序。如果你想让程序按照字母顺序打印出单词,只需要把Set的具体实现类型从HashSet修改为TreeSet。仅仅修改前面一行代码:

Set<String> s = new TreeSet<String>();

将产生下面的输出:

java FindDups i came i saw i left
Duplicate detected: i
Duplicate detected: i
4 distinct words: [came, i, left, saw]


Set接口批量操作(bulk operation)

批量操作尤其适用于Set。当执行批量批量操作相当于执行集合代数意义上的运算。假设s1和s2都是Set。下面是各种批量操作:

  • s1.containsAll(s2) — 如果s2是s1的子集,返回true,否则返回false
  • s1.addAll(s2) — 得到的是s1和s2的并集
  • s1.retainAll(s2) — 得到的是s1和s2的交集
  • s1.removeAll(s2) — 得到的是s1和s2的差集(s1-s2,即所有s1中有但是s2中没有的元素的集合)

为了计算两个集合的并、交、差集而不修改这两个集合,调用者必须先拷贝一份,然后再调用bulk opertaion,比如下面:

Set<Type> union = new HashSet<Type>(s1);
union.addAll(s2);

Set<Type> intersection = new HashSet<Type>(s1);
intersection.retainAll(s2);

Set<Type> difference = new HashSet<Type>(s1);
difference.removeAll(s2);

上面代码的结果集类型是HashSet。

让我们再次回顾之前的FindDups程序。假设你想知道哪些单词只出现一次,哪些单词出现不止一次,但是又不想重复打印单词。那么这种效果可以用两个Set来实现,一个Set包含参数列表中的所有单词,另外一个Set只包含重复出现的单词。那么只出现一次的单词就是这两个Set的差集。下面是代码实现:

import java.util.*;

public class FindDups2 {
    public static void main(String[] args) {
        Set<String> uniques = new HashSet<String>();
        Set<String> dups    = new HashSet<String>();

        for (String a : args)
            if (!uniques.add(a))
                dups.add(a);

        // Destructive set-difference
        uniques.removeAll(dups);

        System.out.println("Unique words:    " + uniques);
        System.out.println("Duplicate words: " + dups);
    }
}

代码运行结果如下:

Unique words:    [left, saw, came]
Duplicate words: [i]

还有一个不那么常见的集合代数操作,那就是对称集合差集 —— 由两个集合中的元素组成,但元素不能包含于两个集合的交集中。下面的代码实现了这种效果:

Set<Type> symmetricDiff = new HashSet<Type>(s1);
symmetricDiff.addAll(s2); // 并集
Set<Type> tmp = new HashSet<Type>(s1);
tmp.retainAll(s2)); // tmp成了交集
symmetricDiff.removeAll(tmp);


Set接口的数组操作

Set接口的数组操作与前面的Collection接口的数组操作没有任何不同。

分享到:
评论

相关推荐

    集合框架List、Map、Set接口及其子类综合对比

    Java基础知识汇总之集合框架List、Map、Set接口及其子类综合对比

    计算机后端-Java-Java核心基础-第25章 集合02 04. 复习:Set接口.avi

    计算机后端-Java-Java核心基础-第25章 集合02 04. 复习:Set接口.avi

    Java集合框架Set接口.pdf

    Java集合框架中的Set接口是一种不允许包含重复元素的集合。Set接口继承自Collection接口,因此它具有Collection接口定义的所有方法。同时,Set接口还具有自己的特殊方法,例如:添加元素、删除元素、判断元素是否...

    Java集合框架.pdf

    1、可扩展性:Java集合框架提供了一组可扩展的接口和类,可让开发人员根据自己的需要实现新的数据结构和算法。 2、高性能:Java集合框架中的数据结构和算法经过优化,可以提供高效的性能。 3、类型安全:Java集合...

    Java集合框架Collection接口.pdf

    其中Collection接口是Java集合框架的基础接口之一,定义了一些基本的集合操作,包括添加元素、删除元素、遍历集合等。在这里,我将为您详细介绍Java集合框架中的Collection接口。 Collection接口是Java集合框架中的...

    精通java集合框架--List,Set..

    “集合框架”由一组用来操作对象的接口组成。不同接口描述不同类型的组。 在很大程度上,一旦您理解了接口,您就理解了框架。 虽然您总要创建接口特定的实现,但访问实际集合的方法应该限制在接口方法的使用上;...

    Java集合框架图

    Java集合List集合Set集合Map集合Collection和collections工具类的框架图

    java集合框架笔记

    List set ArraryList Map java集合框架笔记 基于Array的List,其实就是封装了Array所不具备的一些功能方便我们使用

    java 集合框架

    Java集合框架,set、list接口及其子集,接口的继承关系

    Java集合框架常见面试题

    Java集合框架常见面试题 剖析⾯试最常⻅问题之 Java 集合框架 包含以下几个模块: 1、集合概述 2、Collection子接口之List 3、Collection子接口之Set 4、Map接口 5、Collection工具类 6、其他重要问题

    Java集合Collection、List、Set、Map使用详解编程资料

    Java集合Collection、List、Set、Map使用详解

    Java集合框架总结

    Java集合框架汇总 1.集合框架结构图 1 2.两种特殊的Java容器类List和Set分析 2 3. Collection 接口: 2 4.Iterator 接口: 3 5.List接口: 3 5.1 LinkedList类: 5 5.2 ArrayList类: 5 6.Set接口: 5 7.Map...

    JAVA集合(List,Set,Map)

    Java 2集合框架图 集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。 抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。 实现类:8个实现类(实线表示),...

    java集合资料整理

    集合接口:6个接口,表示不同集合类型,是集合框架的基础。 抽象类:5个抽象类,对集合接口的部分实现。可扩展为自定义集合类。 实现类:8个实现类,对接口的具体实现。 在很大程度上,一旦您理解了接口,您就...

    Java-Java集合体系-List-Set

    内容概要:总结了Java集体体系中的三大集合接口LIst、Set、Map,本文对LIst、Set做出了详细、简要的分析,没有冗长的文章,全是干货,下载即用,其中涉及了其底层实现,面试题必备。 学习收获:通过学习这篇文章,您...

    Java高级程序设计:第7章-集合框架.pptx

    java.util包中定义了各种用于集合操作的类和接口,这些类和接口构成了Java语言的集合框架(Collection Framework)。 Java集合中可以放对象,不能存放基础数据类型数。 Collection Framework 根据不同类型的集合的特点...

    Java集合容器集合框架Set集(与“集合”有关文档共23张).pptx

    Java集合容器集合框架Set集(与“集合”有关文档共23张).pptx

    实验05 Java集合.doc

    掌握集合的概念、体系结构、分类及使用场景 2)了解Set接口及主要实现类(HashSet、TreeSet) 3)了解List接口及主要实现类...2、为什么使用集合框架,而尽可能少用数组作为存储结构? 3、如何使用TreeSet实现第一题?

    java集合知识-map、set等

    Set:元素不可以重复,是无序。p508 Set接口中的方法和Collection一致。 |--HashSet: 内部数据结构是哈希表 ,是不同步的。 如何保证该集合的元素唯一性呢? 是通过对象的hashCode和equals方法来完成对象唯一性的...

    java集合框架专题-java面试经典

    java集合框架专题-java面试经典, 涉及List set Map 等相关知识

Global site tag (gtag.js) - Google Analytics