Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合里面,则添加操作失败,add()方法返回false,且新元素不会被添加入。
1.HashSet是Set的接口的典型实现,大多数时候使用Set集合就是使用这个实现类,HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。HashSet具有以下特点,不能保证元素的排列顺序,可能和添加的顺序不同;HashSet不是同步的,如果有多个线程同是访问一个HashSet,则必须通过代码来保证其同步性;集合元素值可以是null。当向HashSet集合存入一个元素时,HashSet会调用该对象的hashcode()方法来得到该对象的hashCode值,然后提供该hashCode值决定该对象在HashSet中的存储位置。如果有两个元素通过equals()方法比较返回true,但他们的hashCode()方法返回值不相等,HashSet将会把他们存储在不同的位置,依然可以添加成功,也就是说HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode方法返回值也相等。 HashSet中每个能存储元素的“槽位”(solt)通常也称为“桶”(bucket),如果有多个元素的hashCode值相同,但他们通过的equals()方法比较返回false,就需要在一个“桶”里面放入多个元素,这就会导致性能的下降。
2.HashSet还有一个子类LinkedHashSet,LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。也就说遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的的添加顺序来访问里的元素。LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时将会有很好的性能,因为它以丽链表来维护内部顺序。
package com.lanou.test;
import java.util.LinkedHashSet;
public class Demo10 {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedHashSet linkedHashSet=new LinkedHashSet();
linkedHashSet.add("zasas");
linkedHashSet.add("dsakek");
linkedHashSet.add("adsdsd");
linkedHashSet.add("zasdkesd");
System.out.println(linkedHashSet);
}
}
3.TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。与HashSet集合相比,TreeSet还提供了几个额外的方法。Comparator comparator():如果TreeSet采用了定制的顺序,该方法返回定制的排序所使用的Comparator:如果TreeSet采用自然排序,则返回null。Object first()返回集合中的一个元素。Object last()返回集合中的最后一个元素。Object lower(Object e):返回集合中位于指定元素之前的元素。Object higher(Object e)返回集合中位于指定元素之后的元素。Sorted subSet(Object formElement,Object toElement)返回次set的子集合,范围从fromElement(包含)到toElement(不包含)。SortedSet headSet(Object toElement)返回此set的子集合,小于toElement的元素组成。SortedSet tailSet(Object formElement):返回此set的子集合,由大于或等于fromElement的元素组成。
package com.lanou.test;
import java.util.TreeSet;
public class Demo11 {
public static void main(String[] args) {
TreeSet munber=new TreeSet();
munber.add(6);
munber.add(45);
munber.add(12);
munber.add(-9);
System.out.println(munber);
}
}
其实TreeSet会调用集合元素的comparaTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列,这种方式就是自然排序。java还提供了一个Comparable接口,该接口里面定义一个comparaTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象的就可以比较大小了。一个对象调用该方法比较另一个对象大小,如果相等返回0,大于返回正整数。java中常用的类已经实现了Comparable接口,有BigDecimal、BIgInteger、Character、Boolean、String、Date、Time。如果希望TreeSet能正常运作时,TreeSet只能添加同一种类型的对象。定制排序TreeSet的自然排序是根据集合元素的大小,TreeSet将他们按照升序排列,如要让他们实现定制的顺序,就要通过Comparator接口,该接口里面包含一个int compara(T o1,To2)的方法,该方法用于比较o1和o2的大小,因为Comparator接口是个函数是接口,因此可使用lanbda 表达式。
4.EnumSet是专门为枚举设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举在创建EnumSet时显示或隐式地指定。EnumSet的集合也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效、因此EnumSet对象占用的内存很小,且运行效率很好。EnumSet集合不允许加入null元素,如试图添加null元素,EnumSet将抛出NullpointException异常。
5.HashSet和TreeSet是set的两个典型实现,HashSet的性能总是比TreeSet好,特别是添加查询操作,因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只要当需要一个保持排序的Set时,才会用TreeSet,否则都是使用HashSet。HashSet还有个子类LinkedHashSet,对于普通的的插入、删除操作,LinkedHashSet比HashSet要略慢一点,这是维持链表所带来的额外的开销,但由于有链表,遍历LinkedHashSet会更快。EnumSet是所有Set实现类中性能最好的,但它只能保存一个枚举类的枚举值作为集合元素。 Set的三个实现类Hashset TreeSet EnumSet都是线程不安全的。如果有多个线程同时访问一个Set集合,并且有一个线程修改了该Set的集合类,就必须手动保证该Set集合的同步性,通过synchronizedSortedSet包装该set集合。