JavaSE-----Set集合(HashSet类及其特殊子类、TreeSet类--自然排序与定制排序代码实现)、各Set类性能分析

Set集合

set集合类似于一个罐子,可以依次把多个对象放进去,罐子并不能记住顺序,实际上Set集合与Collection集合基本相同,没有额外的方法,只是不允许有重复元素

HashSet类

HashSet的特点:(1)不能保证元素的排列顺序,顺序可能变化
              (2)不同步,多线程同时访问需要手动代码实现
              (3)集合元素值可以使NULL
HashSet存储的问题:存储元素的槽位,通常称之为‘桶’,当多个元素的Hashcode值相同是,我们称之为哈希碰撞,有可能在桶中有多个元素,他们的存储方式是链式的。

hash算法的优点在于速度

详细的解释一下:当从HashSet访问元素时,HashSet先算出该元素的hashcode值,然后直接从该hashcode值对应的位置中取出该元素。

hashcode的重写方法
第一步:根据实例变量计算出一个 int 类型的hashcode值
 实例变量类型       计算方式
 boolean          hashCode=(f?0:1)
 整数类型          hashCode=(int)f
 long             hashCode=(int(f^(f>>>32))
 float            hashCode=Float.floatToIntBits(f);
 引用类型          hashCode=f.hashCode()                 
第二步://计算出多个hashcode值组合并返回,             
 return f1.hashcode()+(int)f2;  同时为了尽可能地避免偶然相等的情况,我们做了改进
 return f1.hashcode()*19+(int)f2*31; //引入两个权重,权重均为素数,且不宜过大引发溢出                            

我们来看看源码:

 public static int hashCode(Object a[]) {
            if (a == null)
                return 0;
            int result = 1;
            for (Object element : a)
                result = 31 * result + (element == null ? 0 : element.hashCode());
            return result;
        }

LinkedHashSet类

LinkedHashSet类是HashSet的一个子类,它同时拥有链表维护次序,当遍历LinkedHashSet类集合元素时,会按照添加的顺序访问集合元素。

举例:

            LinkedHashSet<Object> obj = new LinkedHashSet<>();
            obj.add("aaa");
            obj.add("ccc");
            System.out.println(obj);
            obj.remove("aaa");
            obj.add("aaa");
            System.out.println(obj);
        }
输出LinkedHashSet集合元素时,元素的顺序与输入一致

TreeSet类

TreeSet是SortedSet接口的实现类,可以确保元素处于排序状态。实现方法举例说明:

   TreeSet<Integer> num = new TreeSet<>();
        num.add(5);
        num.add(10);
        num.add(23);
        num.add(-1);
        System.out.println(num);
        System.out.println(num.first());
        System.out.println(num.last());
        System.out.println(num.headSet(4));  //返回小于4的子集
        System.out.println(num.tailSet(5));  //返回大于5的子集
        System.out.println(num.subSet(-2, 11));     // 返回大于-2,小于11的子集

TreeSet采用红黑树的数据结构排序,支持两种排序结构,分别是自然排序和定制排序

自然排序

TreeSet自然排序会调用CompareTo(Object obj)方法来实现,此对象必然实现Comparable接口。举例如下:

class Z implements  Comparable{
   int age;
   public  Z(int age){
       this.age=age;
    }
    public  boolean equals(Object obj){
       return  true;
    }
    public  int compareTo(Object obj){
        return  1;
    }
}
public  class  demo{
    public static void main(String[] args) {
        TreeSet set = new TreeSet();
        Z z1=new Z(6);
        set.add(z1);
        System.out.println(set.add(z1));
        System.out.println(set);
        ((Z) (set.first())).age=9;
        System.out.println(((Z) (set.first())).age);
    }
}

自然排序存储元素时,跟树根节点比较,分左右,比树根小放左边,比树根大放左边,与树根一致是不存储。

定制排序

自然排序会将集合中元素大小按升序排列,然而现实中我们并不一定需要升序排列,可能需要降序排列。通过Comparator接口的 int compare(T o1,T o2)方法,比较大小,通过返回值正负表明大小。正大负小。举例:

class M{
    int age;
    public M(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "M [age:"+age+"]";
    }
}
public class Treeset {
    public static void main(String[] args) {
        Treeset ts = new Treeset((o1,o2) ->{
            M m1 = (M) o1;
            M m2 = (M) o2;
        });
        ts.add(new M(5));
        ts.add(new M(9));
        ts.add(new M(-3));
        System.out.println(ts);
    }
}
定制排序实现降序排列。

注意:通过Comparator对象实现定制排序时,也不可添加不同的对象。定制排序时,不是由TreeSet排序,而是由Comparator对象负责排序当然也可以是Lambda表达式负责。

Lambda表达式

Java 8更新后,支持将代码块作为方法参数,允许使用更简洁的方法建立只有一个抽象方法的接口。

Lambda表达式是吸纳的是匿名方法,当代码块只有一行是,可以不带{},当表达式形参只有一个时,不用带();

Lambda表达式的目标类型必须有明确的函数式接口,只能为函数式接口创建对象,只能实现一个方法,只能为只有一个抽象方法的接口创建对象。

各Set实现类性能分析

总结:HashSet和TreeSet是Set的两个经典实现。在选择上,HashSet的性能总比TreeSet好!!特别是增、删、查上,只有当需要一个排序Set时,才会用TreeSet。

另:HashSet 还有一个子类,LinkedHashSet,因为其特殊的链表结构,所以增、删会慢一点,但遍历性能好一点。

当然,Set三种实现类(Hash、Tree、Enum)都是线程不安全的,多线程操作时,需要手动保证,一般是通过集合工具类的synchronizedSortedSet包装该Set集合。最好在运行开始就定义。

SortdeSet s=Collection.synchronizedSortdeSet(new Treeset());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值