Java集合之Set集合

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()来实现线程安全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值