一、Set 接口概述
1、Set 接口是 Collection 的子接口,set 接口没有提供额外的方法;
2、Set接口:存储无序的、不可重复的数据,Set 接口中会以某种规则保证存入的元素不出现重复。
3、Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败;
4、Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法;
5、Set 集合不是同步的,多线程不安全的;
6、Set 接口的结构
特点:查询速度快,不重复,没有索引。
二、常用实现类
1、HashSet
HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值。
构造方法:
HashSet() :构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75
源码:
2、LinkedHashSet
作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,LinkedHashSet效率高于HashSet。
构造方法:
LinkedHashSet(): 构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set
LinkedHashSet(int initialCapacity) :构造一个带指定初始容量和默认加载因子 (0.75) 的新空链接哈希 set
源码:
3、TreeSet
TreeSet:可以按照添加对象的指定属性,进行排序,底层使⽤红⿊树,能够按照添加元素的顺序进⾏排序,排序的⽅式有⾃然排序和定制排序。
构造方法:
TreeSet() :构造一个新的空 set,该 set 根据其元素的自然顺序进行排序
TreeSet(Comparator<? super E> comparator) :构造一个新的空 TreeSet,它根据指定比较器进行排序
源码:
4、小结
(1)Set 的内部实现其实是一个 Map,即HashSet的内部实现是一个HashMap,TreeSet的内部实现是一个TreeMap,LinkedHashSet的内部实现是一个LinkedHashMap。
(2)但是 Set 中只有一个元素,又是怎么变成(key,value)的呢?
以 HashSet 的 add 方法为例:
原来是,把添加到 Set 中的元素作为内部实现 map 的 key,然后用一个常量对象 PRESENT 对象,作为value。
所有的 HashSet 共用同一个PRESENT对象,所有的 TreeSet 共用同一个 PRESENT对象,所有的 LinkedHashSet 共用同一个 PRESENT 对象。
这是因为 Set 的元素不可重复和 Map 的 key 不可重复有相同特点。Map 有一个方法 keySet() 可以返回所有 key。
三、实现类的对比
1、Set 集合是有序的吗?
① 如果按照元素的存储顺序来说,有一些是可以保证的,有一些是不能保证的。唯有 LinkedHashSet可以保证元素添加的顺序
② 如果按照元素的大小顺序来说,有一些是可以保证的,有一些是不能保证的。唯有 TreeSet可以保证元素的大小顺序
③ HashSet:既不能保证添加顺序,也不能保证大小顺序。是完全无序的。
2、HashSet 与 LinkedHashSet 区别?
HashSet:完全无序。
LinkedHashSet:是按照添加顺序来存储的。LinkedHashSet 是 HashSet 的子类,比 HashSet 多维护了添加的顺序。
当既想要实现集合的元素的不可重复性,又想要保证元素的添加顺序,就选择使用LinkedHashSet(效率低),否则就用List系列或HashSet。
3、HashSet 与 TreeSet 的区别?
HashSet:完全无序。
TreeSet:是按照存储元素的大小来排序,当你需要元素不可重复,又要给元素排大小时,就用TreeSet。
注意:要用到TreeSet,存储的元素对象一定要实现 要用到TreeSet,一定要用java.lang.Comparable或java.util.Comparator
3、如何保证元素不可重复的呢?(如何判断两个元素是重复的呢)
(1)HashSet 和 LinkedHashset 集合:
① 先比较元素的 hash 值,如果 hash 值不一样,说明两个元素一定不相同。
② 如果 hash 值一样,再调用 equals 方法比较
(2)TreeSet 集合:
按照存储元素的大小来决定元素是否相同,如果两个元素大小“相等”就是相同的元素。即必须实现 java.lang.Comparable或java.util.Comparator。
四、Set 的无序性与不可重复的理解
1、无序性
无序性:不等于随机性。⽆序性是指存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。
2、不可重复性
不可重复性:保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一个。
3、
四、Set 中方法
Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。
五、如何保证数据的一致性(不可重复性)?
要求:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()
要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。