Set接口
首先Set集合不能拥有相同的元素,它与Collection的方法上没有太多的区别,只是行为不同,即不能有相同元素.
HashSet实现类
HashSet是Set的接口的典型实现,大多数时都会使用HashSet,使用的时Hash算法来存储集合中的元,所以有很好的存取和查找性能.
HashSet的特点:
1.不能保证元素的排列顺序,顺序可能和添加顺序不同,可能会有变化
2.HashSet不是同步的,可以通过代码保证其同步
3.集合的元素值可以是null
当一个HashSet集合存入一个元素时,HashSet会调用该对象的hashCode()方法来得到hashCode值,根据值决定HashSet中的存储位置.
但如果当两对象的hashCode值不相等,则不会调用equal()方法,即就算两者的值是相等,HashSet会将它们存储在不同位置,依然可以添加成功,这是不可取的,违反了Set的规则
当两对象的hashCode值相等,调用equal值不相等时,HashSet将会试图将它们使用链式结构保存在同一位置,但这种情况会导致HashSet的性能下降,因为HashSet是根据元素的hashCode值来快速定位的
所以当某个类的对象保存到HashSet集合中,重写这个类的equals()方法和hashCode()方法时,应尽量保证两个对象通过equals()方法比较返回true时,他们的hashCode()方法返回值也为true
当HashSet集合中添加了可变对象也要极其小心,若是修改了集合元素中参与计算hashCode(),equals()的实例变量,可能会导致HashSet无法正确操作这些集合元素,如下
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetTest {
public static void main(String[] args) {
Set hs = new HashSet();
hs.add(new A(1));
hs.add(new A(5));
hs.add(new A(10));
hs.add(new A(20));
System.out.println("原来中集合的元素:"+hs+" ");
System.out.println("-------------------------");
Iterator it = hs.iterator();
//取出第一个元素
A one = (A) it.next();
one.count = 5;
System.out.println("修改后的集合元素:"+ hs + " ");
System.out.println("-------------------------");
//删除一个count为5的对象
hs.remove(new A(5));
System.out.println("删除了一个集合元素为5的元素:" + hs + " ");
System.out.println("-------------------------");
System.out.println("是否包含了1的对象:" +hs.contains(new A(1)));
System.out.println("是否包含了5的对象:" +hs.contains(new A(5)));
}
}
控制台打印结果
原来中集合的元素:[A的count值:1, A的count值:20, A的count值:5, A的count值:10]
-------------------------
修改后的集合元素:[A的count值:5, A的count值:20, A的count值:5, A的count值:10]
-------------------------
删除了一个集合元素为5的元素:[A的count值:5, A的count值:20, A的count值:10]
-------------------------
是否包含了1的对象:false
是否包含了5的对象:false
LinkedHashSet
LinkedHashSet是HashSet的子类,它与HashSet的区别是,元素的顺序总是与添加的顺序,这是使用了链表维护元素的次序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时将有很好的性能,因为它以链表来维护内部顺序.
TreeSet
TreeSet是SortSet接口的实现类,TreeSet不是以插入顺序进行排序的,而是根据元素实际值的大小来进行排序的.
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小的关系,然后将集合元素按升序排序,为自然排序.
Java9改进了TreeSet实现,采用自然排序的Set集合的元素没有实现Comparable,程序会引发ClassCaseException异常
TreeSet和HashSet一样不要修改实例变量,会导致无法删除变量,为了让程序健壮,不要修改放入HashSet和TreeSet集合中元素的关键实例变量.
定制排序,可以通过Comparator接口的帮助来制定自己的排序代码
EnumSet
EnumSet是一个转为枚举类的集合类,EnumSet中所有的元素都必须是指定的枚举类型的枚举值,其集合元素也是有序的,EnumSet以枚举在Enum类内的定义顺序来决定集合元素的顺序.
EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑,高效,因此EnumSet对象占用内存很小,而且运行效率好.
EnumSet步允许加入null元素
各Set实现类的性能分析
HashSet和TreeSet是Set两个典型实现,HashSet的性能总比TreeSet好,特别是在添加,查询元素等操作,因为TreeSet需要额外的红黑数算法来维护集合元素的次序.
LinkedHashSet因为有了链表的维护,在遍历时会比较方便
EnumSet性能最好
上述的Set的实现类,线程都是不安全的,可以通过Collections.synchronizedSortedSet()来实现线程安全