Java Set基础必知必会

Set集合,它类似与一个罐子,程序可以一次把多个对象“丢进”Set集合,而Set集合不能记住元素的添加顺序,Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。
在这里插入图片描述

一、HashSet类

HashSet类是Set接口的典型实现,HashSet按照Hash算法来存储集合中的元素,因此具有很好的存取和查找性能
HashSet具有以下特点:

  1. 不能保证元素的排列顺序,顺序可能发生变化。
  2. HashSet不是同步的,如果多个线程同时访问一个HashSet,则必须通过代码来保证同步。
  3. 集合的元素值可以是null。

HashSet集合判断两个元素相等的标准是:两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。
如果两个对象通过equals()方法比较返回true,但它们的hashCode()方法的返回值不相等,HashSet将会把它们存储在不同的位置,依然可以添加成功。
如果两个对象的hashCode()方法返回的hashCode值相同,但是它们通过equals()方法比较返回false时,两个对象的hashCode相同,HashSet将试图把它们保存在同一位置,但又不行,所以实际上会在这个位置用链式结构来保存多个对象;而HashSet访问集合元素时也是根据元素的hashCode值来快速定位的,如果HashSet中两个以上的元素具有相同的hashCode值,将会导致性能下降。


HashSet中每个能存储元素的“槽位”(slot)通常称为“桶”(bucket),如同上文所说,多个元素通过equals()比较返回false,但是hashCode相同,就需要在一个bucket中存放多个元素,将会导致性能下降。
HashSet的默认容量为16,加载因子为0.75(即元素到达默认用量的0.75倍后开始扩容),每次扩容为原来的2倍。
HashSet的底层是基于HashMap实现的。

二、LinkedHashSet类

LinkedHashSet作为HashSet的子类,它也是通过hashCode值来决定元素的存储位置,但它同时通过链表来维护元素次序,这样使得的元素看起来是以插入的顺序保存的,也就是说在遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。这样用链表来维护使得LinkedHashSet的性能略低于HashSet的性能,但是在迭代访问Set里的全部元素时将会有很好的性能。
它底层是基于LinkedHashMap来实现的

三、TreeSet类

TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗示的,TreeSet可以确保集合元素处于排序状态(TreeSet并不是按照插入顺序的,而是根据元素的实际值的大小来进行排序的)。
与HashSet集合采用的hash算法来决定元素的存储位置不同,TreeSet是基于红黑树的数据结构来存储集合元素。TreeSet支持两种排序方法:自然排序和定制排序。默认情况采取自然排序(即从小到大)。
如果希望TreeSet能够正常的运作,那么只在TreeSet里加入一种类型的对象就好。对于TreeSet集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过compareTo(Object obj)方法比较是否返回0,如果返回0就认为它们相等,否则就认为他们不相等

四、EnumSet类

EnumSet类是一个专为枚举类设计的集合类,EnumSet中所有的元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显示或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类的定义顺序来决定集合元素的顺序。
EnumSet在内部以向量的形式存储,这种存储形式非常的紧凑和高效,因此EnumSet对象占用内存很小,而且运行效率很好。
EnumSet集合不允许加入null,如果试图插入null元素,EnumSet将抛出NullPointerException异常。

五、各个Set实现类的性能分析

对于HashSet和TreeSet,两者都是Set的典型实现,HashSet的性能总是比TreeSet的性能要好,尤其是常用的增删查改,因为TreeSet需要额外的红黑树算法来维护集合元素的次序,只有当需要一个需要保持排序的Set的时候,才应该考虑使用TreeSet,否则都应该使用HashSet。
对于HashSet和LinkedHashSet,在进行插入,删除等操作的时候要比HashSet慢一点,因为维护链表需要额外的开销,但是遍历LinkedHashSet比遍历HashSet能快一点。
EnumSet是所有Set实现类中性能最好的,但是它只能保存同一个枚举类的枚举值作为集合元素。
必须指出的是Set的三个实现类HashSet、TreeSet和EnumSet都是线程不安全的。

猜你喜欢

转载自blog.csdn.net/laobanhuanghe/article/details/101031166