Set

1.5.1        概述

Java 中的Set和正好和数学上直观的集(set)的概念是相同的。Set最大的特性就是不允许在其中存放的元素是重复的。根据这个特点,我们就可以使用Set 这个接口来实现前面提到的关于商品种类的存储需求。Set 可以被用来过滤在其他集合中存放的元素,从而得到一个没有包含重复新的集合。

1.5.2        常用方法

按照定义,Set 接口继承 Collection 接口,而且它不允许集合中存在重复项。所有原始方法都是现成的,没有引入新方法。具体的 Set 实现类依赖添加的对象的 equals() 方法来检查等同性。

我们简单的描述一下各个方法的作用:

public int size() :返回set中元素的数目,如果set包含的元素数大于Integer.MAX_VALUE,返回Integer.MAX_VALUE

public boolean isEmpty() :如果set中不含元素,返回true

public boolean contains(Object o) :如果set包含指定元素,返回true

public Iterator iterator()

返回set中元素的迭代器

元素返回没有特定的顺序,除非set是提高了该保证的某些类的实例

public Object[] toArray() :返回包含set中所有元素的数组

public Object[] toArray(Object[] a) :返回包含set中所有元素的数组,返回数组的运行时类型是指定数组的运行时类型

public boolean add(Object o) :如果set中不存在指定元素,则向set加入

public boolean remove(Object o) :如果set中存在指定元素,则从set中删除

public boolean removeAll(Collection c) :如果set包含指定集合,则从set中删除指定集合的所有元素

public boolean containsAll(Collection c) :如果set包含指定集合的所有元素,返回true。如果指定集合也是一个set,只有是当前set的子集时,方法返回true

public boolean addAll(Collection c) :如果set中中不存在指定集合的元素,则向set中加入所有元素

public boolean retainAll(Collection c) :只保留set中所含的指定集合的元素(可选操作)。换言之,从set中删除所有指定集合不包含的元素。 如果指定集合也是一个set,那么该操作修改set的效果是使它的值为两个set的交集

public boolean removeAll(Collection c) :如果set包含指定集合,则从set中删除指定集合的所有元素

public void clear() :从set中删除所有元素

“集合框架” 支持 Set 接口两种普通的实现:HashSet 和 TreeSet以及LinkedHashSet。下表中是Set的常用实现类的描述:

简述

实现

操作特性

成员要求

Set

成员不能重复

HashSet

外部无序地遍历成员。

成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

TreeSet

外部有序地遍历成员;

附加实现了SortedSet, 支持子集等要求顺序的操作

成员要求实现Comparable接口,或者使用Comparator构造TreeSet。成员一般为同一类型。

LinkedHashSet

外部按成员的插入顺序遍历成员

成员与HashSet成员类似

在更多情况下,您会使用 HashSet 存储重复自由的集合。同时HashSet中也是采用了Hash算法的方式进行存取对象元素的。所以添加到 HashSet 的对象对应的类也需要采用恰当方式来实现 hashCode() 方法。虽然大多数系统类覆盖了 Object 中缺省的 hashCode() 实现,但创建您自己的要添加到 HashSet 的类时,别忘了覆盖 hashCode()。

对于Set的使用,我们先以一个简单的例子来说明:

import java.util.*;

public class HashSetDemo {

   public static void main(String[] args) {

      Set set1 = new HashSet();

      if (set1.add("a")) {//添加成功

         System.out.println("1 add true");

      }

      if (set1.add("a")) {//添加失败

         System.out.println("2 add true");

      }    

      set1.add("000");//添加对象到Set集合中

      set1.add("111");

      set1.add("222");

      System.out.println("集合set1的大小:"+set1.size());

      System.out.println("集合set1的内容:"+set1);

      set1.remove("000");//从集合set1中移除掉 "000" 这个对象

      System.out.println("集合set1移除 000 后的内容:"+set1);

      System.out.println("集合set1中是否包含000 :"+set1.contains("000"));

      System.out.println("集合set1中是否包含111 :"+set1.contains("111"));

      Set set2=new HashSet();

      set2.add("111");

      set2.addAll(set1);//将set1 集合中的元素全部都加到set2中

      System.out.println("集合set2的内容:"+set2);

      set2.clear();//清空集合 set1 中的元素

      System.out.println("集合set2是否为空 :"+set2.isEmpty());

      Iterator iterator = set1.iterator();//得到一个迭代器

      while (iterator.hasNext()) {//遍历

         Object element = iterator.next();

         System.out.println("iterator = " + element);

      }

      //将集合set1转化为数组

      Object s[]= set1.toArray();

      for(int i=0;i<s.length;i++){

         System.out.println(s[i]);

      }

   }

}

程序执行的结果为:

1 add true

集合set1的大小:4

集合set1的内容:[222, a, 000, 111]

集合set1移除 000 后的内容:[222, a, 111]

集合set1中是否包含000 :false

集合set1中是否包含111 :true

集合set2的内容:[222, a, 111]

集合set2是否为空 :true

iterator = 222

iterator = a

iterator = 111

222

a

111

从上面的这个简单的例子中,我们可以发现,Set中的方法与直接使用Collection中的方法一样。唯一需要注意的就是Set中存放的元素不能重复。

我们再看一个例子,来了解一下其它的Set的实现类的特性:

package c08;

import java.util.*;

public class SetSortExample {

  public static void main(String args[]) {

    Set set1 = new HashSet();

    Set set2 = new LinkedHashSet();

    for(int i=0;i<5;i++){

      //产生一个随机数,并将其放入Set中

      int s=(int) (Math.random()*100);

       set1.add(new Integer( s));

       set2.add(new Integer( s));

       System.out.println("第 "+i+" 次随机数产生为:"+s);

    }

    System.out.println("未排序前HashSet:"+set1);

    System.out.println("未排序前LinkedHashSet:"+set2);

    //使用TreeSet来对另外的Set进行重构和排序

    Set sortedSet = new TreeSet(set1);

    System.out.println("排序后 TreeSet :"+sortedSet);

  }

}

该程序的一次执行结果为:

第 0 次随机数产生为:96

第 1 次随机数产生为:64

第 2 次随机数产生为:14

第 3 次随机数产生为:95

第 4 次随机数产生为:57

未排序前HashSet:[64, 96, 95, 57, 14]

未排序前LinkedHashSet:[96, 64, 14, 95, 57]

排序后 TreeSet :[14, 57, 64, 95, 96]

从这个例子中,我们可以知道HashSet的元素存放顺序和我们添加进去时候的顺序没有任何关系,而LinkedHashSet 则保持元素的添加顺序。TreeSet则是对我们的Set中的元素进行排序存放。

一般来说,当您要从集合中以有序的方式抽取元素时,TreeSet 实现就会有用处。为了能顺利进行,添加到 TreeSet 的元素必须是可排序的。 而您同样需要对添加到TreeSet中的类对象实现 Comparable 接口的支持。对于Comparable接口的实现,在前一小节的Map中已经简单的介绍了一下。我们暂且假定一棵树知道如何保持 java.lang 包装程序器类元素的有序状态。一般说来,先把元素添加到 HashSet,再把集合转换为 TreeSet 来进行有序遍历会更快。这点和HashMap的使用非常的类似。

其实Set的实现原理是基于Map上面的。通过下面我们对Set的进一步分析大家就能更加清楚的了解这点了。

1.5.3         实现原理

Java中Set的概念和数学中的集合(set)一致,都表示一个集内可以存放的元素是不能重复的。

前面我们会发现,Set中很多实现类和Map中的一些实现类的使用上非常的相似。而且前面再讲解Map的时候,我们也提到:Map中的“键值对”,其中的“键”是不能重复的。这个和Set中的元素不能重复一致。我们以HashSet为例来分析一下,会发现其实Set利用的就是Map中“键”不能重复的特性来实现的。

先看看HashSet中的有哪些属性:

再结合构造函数来看看:

通过这些方法,我们可以发现,其实HashSet的实现,全部的操作都是基于HashMap来进行的。我们看看是如何通过HashMap来保证我们的HashSet的元素不重复性的:

看到这个操作我们可以发现HashSet的巧妙实现:就是建立一个“键值对”,“键”就是我们要存入的对象,“值”则是一个常量。这样可以确保,我们所需要的存储的信息之是“键”。而“键”在Map中是不能重复的,这就保证了我们存入Set中的所有的元素都不重复。而判断是否添加元素成功,则是通过判断我们向Map中存入的“键值对”是否已经存在,如果存在的话,那么返回值肯定是常量:PRESENT ,表示添加失败。如果不存在,返回值就为null 表示添加成功。

我们再看看其他的方法实现:

了解了这些后,我们就不难理解,为什么HashMap中需要注意的地方,在HashSet中也同样的需要注意。其他的Set的实现类也是差不多的原理。

至此对于Set我们就应该能够比较好的理解了。

1.6        总结:集合框架中常用类比较

用“集合框架”设计软件时,记住该框架四个基本接口的下列层次结构关系会有用处:

  • Collection 接口是一组允许重复的对象。
  • Set 接口继承 Collection,但不允许重复。
  • List 接口继承 Collection,允许重复,并引入位置下标。
  • Map 接口既不继承 Set 也不继承 Collection, 存取的是键值对

我们以下面这个图表来描述一下常用的集合的实现类之间的区别:

Collection/Map

接口

成员重复性

元素存放顺序(Ordered/Sorted

元素中被调用的方法

基于那中数据结构来实现的

HashSet

Set

Unique elements

No order

equals()

hashCode()

Hash 表

LinkedHashSet

Set

Unique elements

Insertion order

equals()

hashCode()

Hash 表和双向链表

TreeSet

SortedSet

Unique elements

Sorted

equals()

compareTo()

平衡树(Balanced tree)

ArrayList

List

Allowed

Insertion order

equals()

数组

LinkedList

List

Allowed

Insertion order

equals()

链表

Vector

List

Allowed

Insertion order

equals()

数组

HashMap

Map

Unique keys

No order

equals()

hashCode()

Hash 表

LinkedHashMap

Map

Unique keys

Key insertion order/Access order of entries

equals()

hashCode()

Hash 表和双向链表

Hashtable

Map

Unique keys

No order

equals()

hashCode()

Hash 表

TreeMap

SortedMap

Unique keys

Sorted in key order

equals()

compareTo()

平衡树(Balanced tree)

J2SE知识点摘记(二十五)的更多相关文章

  1. J2SE知识点摘记(二十六)

    为了用“集合框架”的额外部分把排序支持添加到 Java 2 SDK,版本 1.2,核心 Java 库作了许多更改.像 String 和 Integer 类如今实现 Comparable 接口以提供自然 ...

  2. J2SE知识点摘记(二十四)

     覆写hashCode() 在明白了HashMap具有哪些功能,以及实现原理后,了解如何写一个hashCode()方法就更有意义了.当然,在HashMap中存取一个键值对涉及到的另外一个方法为equa ...

  3. J2SE知识点摘记(二十二)

    Map 1.4.1        概述 数学中的映射关系在Java中就是通过Map来实现的.它表示,里面存储的元素是一个对(pair),我们通过一个对象,可以在这个映射关系中找到另外一个和这个对象相关 ...

  4. J2SE知识点摘记(二十)

    List 1.3.1        概述 前面我们讲述的Collection接口实际上并没有直接的实现类.而List是容器的一种,表示列表的意思.当我们不知道存储的数据有多少的情况,我们就可以使用Li ...

  5. J2SE知识点摘记(二十三)

    我们简单介绍一下这个接口: 1.4.3        Comparable 接口 在 java.lang 包中,Comparable 接口适用于一个类有自然顺序的时候.假定对象集合是同一类型,该接口允 ...

  6. J2SE知识点摘记(二)

    1.    对象的声明 "类名 对象名 = new 类名();"例子:Person P;//先声明一个Person类的对象p p=new Person();//用new关键字实例化 ...

  7. J2SE知识点摘记(二十一)

    实现原理 前面已经提了一下Collection的实现基础都是基于数组的.下面我们就已ArrayList 为例,简单分析一下ArrayList 列表的实现方式.首先,先看下它的构造函数. 下列表格是在S ...

  8. 小小知识点(二十五)5G关键技术——Massive MIMO(大规模天线阵列)和beamforming(波束成形)

    转自http://www.elecfans.com/d/949864.html 多输入多输出技术(Multiple-Input Multiple-Output,MIMO)是指在发射端和接收端分别使用多 ...

  9. JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

    JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...

随机推荐

  1. 【衡阳八中noip模拟题】国色天香

    庭前芍药妖无格,池上芙蕖净少情.唯有牡丹真国色,花开时节动京城.——唐·刘禹锡<赏牡丹>芍药花再红终究妖艳无格.终不及牡丹,国色天香.——乌拉那拉氏宜修华妃总是想要用自己的气焰打压皇后,正 ...

  2. 移动网络山寨版(OpenBTS)的意义或者无意义 【1】

    在美国内华达州北部,靠近加州的峡谷中,有一片平坦的沙漠,名叫黑岩沙漠(Black Rock Desert).自从1986年以来,每年夏天,在这片沙漠中,都会举办一个为期八天的狂欢节.这个狂欢节的名字叫 ...

  3. AJP协议总结与分析

    Tomcat服务器通过Connector连接器组件与客户程序建立连接,Connector组件负责接收客户的请求,以及把Tomcat服务器的响应结果发送给客户.默认情况下,Tomcat在server.x ...

  4. Windows Azure 社区新闻综述(#68 版)

    欢迎查看最新版本的每周综述,其中包含有关云计算和 Windows Azure 的社区推动新闻.内容和对话. 以下是过去一周基于您的反馈汇集在一起的内容: 文章.视频和博客文章 在 Windows Az ...

  5. C++ 之再继续

    1C++函数重载,内联函数(for程序性能优化),函数递归

  6. 将Dictionary序列化为json数据 、json数据反序列化为Dictionary

    需要引用System.Web.Extensions  dll类库 /// <summary> /// 将json数据反序列化为Dictionary /// </summary> ...

  7. Yii国际化

    Yii版本:1.1.13 1.将CMessageSource的$forceTranslation属性改为true Yii::app()->messages->forceTranslatio ...

  8. Advanced Fruits(好题,LCS的模拟)

    Advanced Fruits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  9. 分布式传输协调程序MSDTC配置

    尊重原著作:本文转载自http://blog.csdn.net/wilsonke/article/details/8468438 配置说明文件:http://files.cnblogs.com/hlx ...

  10. spring加载jar包中多个配置文件

    转自:http://www.cnblogs.com/GarfieldTom/p/3723915.html <import resource="classpath*:applicatio ...