10 Java集合 - Set集合
10.1 Set集合
Set接口继承Collection接口,没有提供额外的方法。Set集合不允许包含相同的元素,向Set集合添加已存在的元素时,add()方法返回false。
10.2 HashSet类
HashSet按Hash算法存储集合中的元素,具有良好的性能。Hash会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在集合里的存储位置。即HashSet集合采用hash算法来决定元素的存储位置。
HashSet中每个能存储元素的位置被称为“桶”。
HashSet具有如下特点:
- 元素的排列顺序与添加顺序不一定相同。
- 不是线程同步的。
- 集合元素可以是null。
HashSet判断两个元素相等的标准:
两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。
HashSet重写equals和hashCode方法的规则:
如果两个对象通过equals()方法比较返回true,这两个对象的hashCode()值也应该相同。
注意:如果HashSet存储了可变类,对某一个元素的更改致使集合中出现两个相同的元素,未被修改的元素可以被删除,修改后的元素无法被删除。因为HashSet根据hashCode值找到存储位置,然后用equals判断相等。
10.3 LinkedHashSet类
LinkedHashSet类是HashSet类的子类,根据元素的hashCode值来决定元素的存储位置,使用链表维护元素的添加次序。遍历LinkedHashSet集合里的元素时,LinkedHashSet会按照元素的添加顺序来访问集合里的元素。
10.4 TreeSet类
TreeSet类是SortedSet接口的实现类,TreeSet集合内的元素处于有序状态。TreeSet采用红黑树的数据结构来存储集合元素。TreeSet中应添加同一种类型的对象。
TreeSet集合新增如下方法:
- Comparator comparator():如果TreeSet使用的定制排序,此方法将返回使用的Comparator;若使用了自然排序,则返回null。
- Object first():返回集合中的第一个元素。
- Object last():返回集合中的最后一个元素。
- Object lower(Object o):小于o的最大元素,o不需要存在集合中。
- Object higher(Object o):大于o的最小元素,o不需要存在集合中。
- SortedSet subSet(Object form, Object to):返回form(包括)到to(不包括)之间的元素作为子集合。
- SortedSet headSet(Object to):返回小于to的元素作为子集合。
- SortedSet tailSet(Object from):返回大于或等于from的元素作为子集合。
实现了Compable接口的常用类及比较方式:
- BigDecimal和所有的数值型对应的包装类。
- Character按UNICODE值进行比较。
- Boolean按true大于false比较。
- String按字符串中字符的UNICODE值进行比较。
- Date、Time类,后面的日期时间比前面的大。
自然排序:
TreeSet会调用集合元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合元素按升序排序,即为自然排序。
如果试图把一个对象添加到TreeSet时,该对象的类必须实现Comparable接口。如果对象的类未实现Comparable接口,那么在加入元素和取出元素时,程序将会抛出ClassCastException异常。
注意:如果TreeSet集合存储了可变类,对某一个元素的更改致使集合中出现两个相同的元素,则未被修改的和修改以后的元素均不能被成功删除。只有删除其他未被修改的元素,并且TreeSet对元素重新索引之后,发生重复的元素才可以被删除。
定制排序:
创建TreeSet对象时传入一个Comparator实现类的对象,并且重写了int compare(T o1, T o2)方法。此时对象的类无须实现Comparable接口。
TreeSet判断两个元素相等的标准:
两个对象通过compareTo(Object o)方法比较返回0。
TreeSet重写equals和compareTo方法的规则:
如果两个对象通过equals方法比较返回true时,这两个对象通过compareTo方法比较应返回0。
10.5 EnumSet类
EnumSet是专门为枚举设计的集合类,EnumSet中的所有元素必须为指定枚举类型的枚举值。EnumSet按枚举值在枚举类中的定义顺序对集合元素进行排序。
EnumSet内部以位向量的形式进行存储。数据存储紧凑且高效,占用内存小,运行效率好。
Enum集合不允许加入null元素。
EnumSet类提供如下类方法来创建对象(未提供构造器):
- EnumSet allOf(Class enumType):创建一个包含指定枚举类所有枚举值的集合。
- EnumSet complementOf(EnumSet s):创建一个EnumSet相对枚举类为补集的集合。
- EnumSet copyOf(Collection c):根据只包含相同枚举类枚举值的普通集合来创建。
- EnumSet copyOf(EnumSet s):根据EnumSet集合来创建,两个集合有相同的枚举值。
- EnumSet noneOf(Class enumType):创建一个类型为指定枚举类的空集合。
- EnumSet of(E first/E... rest):创建一个包含一个或多个枚举值的集合。
- EnumSet range(E from, E to):根据枚举类中form到to之间的枚举值创建集合,包含两边值。
10.6 各Set类的性能分析
HashSet的性能总是比TreeSet好,只有当需要一个保持排序的Set是,才考虑使用TreeSet。 LinkedHashSet在插入删除时,性能比HashSet差,但遍历元素时却更快。EnumSet是所有集合中性能最好的,但是只能保存同一枚举类中的枚举值。
HashSet、TreeSet、EnumSet都是线程不安全的。