java进阶:Set接口

五.Set接口

1.特点

不包含重复元素的集合,没有索引

元素的存储没有顺序,所以存储和取出的顺序不同

取出元素的方式包括迭代器和增强for循环

Set集合常用的实现类包括:

HashSet集合与LinkedHashSet集合

六.HashSet(哈希表)

1.特点:

底层数据结构为哈希表

存储,取出都比较快

线程不安全,运行速度快

不保证Set的迭代顺序

2.哈希表的数据结构:

  • 加载因子:表中填入的记录数/哈希表的长度
    例如:加载因子是 0.75 代表:数组中的16个位置, 其中存入 16 * 0.75 = 12个元素。
  • 如果在存入第十三个( > 12 )元素,导致存储链子过长,会降低哈希表的性能,那么此时会扩充哈希表(再哈希),底层会开辟一个长度为原长度2倍的数组,把老元素拷贝到新数组中,再把新元素添加数组中。
    当 存入元素数量 > 哈希表长度 * 加载因子,就要扩容,因此加载因子决定扩容时机

3.字符串对象的哈希值:

对象的哈希值,是普通的十进制整数,Object类的方法public int hashcode()来计算,计算结果是int整数

String类重写了hashCode()方法

4.哈希表的存储过程

存取原理:

每存入一个新元素需要三步:

首先调入本类的hashCode()方法算出哈希值

在容器中找是否与新元素哈希值相同的老元素,如果没有相同的就直接存入

假如相同,新元素会与索引位置的老元素利用equals方法进行对比,如果全部返回false,说明没有重复,可以存入

5.哈希表的存储自定义对象

自定义对象需要重写hashCode()和equals(),来保证存入对象的不重复

public int hashCode(){

        return name.hashCode()+age+id;

}

public boolean equals(Object obj){

        if(this==obj)

                return true;

        if(obj==null)

                return false;        

        if(obj instanceof Student){

                Student s=(Student)obj;

                return name.equals(s.name)&&age==s.age&&id==s.id;

                }

        return false

}

6.LinkedHashSet集合

LinkedHashSet基于链表的哈希表实现,继承自HashSet

LinkedHashSet自身特性:

具有顺序,存储和取出的顺序相同,线程不安全,运行速度快

public static void main(String[] args){

        LinkedHashSet<Integer>link =new LinkedHashSet<Integer>();

        link.add(123);

        link.add(44);

        link.add(33);

        link.add(33);

        System.out.println(link);

}

7.ArrayList,HashSet判断对象是否重复的原因

ArrayList的contains原理:底层依赖于equals()

ArrayList的contains方法调用时,传入的元素调用equals方法依次与集合中的老元素相比较,从而根据布尔值判断是否有重复元素

此时,当Array List存放自定义类型时,由于自定义类型在未重写equals方法之前,判断是否重复的依据是地址值,所以如果、想根据内容判断是否为重复元素,需要重写元素的equals方法

Hash Set的add()和contain()底层都依赖hashCode()与equals()

Set集合不能存放重复元素,其添加方法在添加时会判断是否有重复元素,有重复不添加,没重复则添加。
HashSet集合由于是无序的,其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:

1. 先判断新元素与集合内已经有的旧元素的HashCode值
2. 如果不同,说明是不同元素,添加到集合。
3. 如果相同,再判断equals比较结果。返回true则相同元素;返回false则不同元素,添加到集合。
所以,使用HashSet存储自定义类型,如果没有重写该类的 hashCode()与equals(),则判断重复时,使用的是地址值,如果想通过内容比较元素是否相同,需要重写该元素类的 hashcode()与equals()。

七、TreeSet

1.概述

  • Set 的另外一种实现,底层由 红黑树 实现;也就是说TreeSet会根据元素的大小关系,将元素默认从小到大排列
  • 特点
    • 元素无序(迭代或者存储顺序和插入顺序)
    • 不能存储重复元素
    • 没有位序
  • Comparator comparator();如果TreeSet采用了定制排序,则该方法返回定制排序所使用 Comparator;如果TreeSet采用了自然排序,则返回null;

2. TreeSet如何实现,不能存储重复元素

  • 其实,在真正的添加元素,treeset 的 add方法 会搜索整颗红黑树(这个元素值,是否已经存在于当前集合,如果存在,则不添加,不存在,就添加)

3. 向TreeSet中放入,自定义的类的对象

  • 如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现Comparable接口,否则程序会抛出异常 java.lang.ClassCastException
现象:直接向一个 TreeSet 中放入自定义类型的对象,发现直接抛出异常
原因:TreeSet 不知道如何对自定义的类对象进行排序,不像字符串可以根据字典顺序
  • 如何向TreeSet中放入自定义类型的对象?
通过某种方式告诉  TreeSet 我们  自定义对象的比较规则
  • 如何自定义比较规则?
  • 第一种方式:放入TreeSet 中的元素实现Comparable接口,根据 CompareTo 方法来指定比较规则:比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。负整数 -> 小于,0 -> 等于,正整数 -> 大于
//compareTo方法
@Override
public int compareTo(Student o) {
    int result;
    if(age == o.age) {
        //当两个同学的年龄形同的时候,进一步按照名字排序
       result =  name.compareTo(o.name);
    } else if(age > o.age) {
        result = 100;
    } else {
        result = -34;
    }
    return result;
}
  • 第二种方式:给 TreeSet 对象定义比较器Comparator
//通过比较器,来制定比较的规则
TreeSet<Student> students = new TreeSet<>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
    return o1.getAge() - o2.getAge();
    }
}); 

4. 注意事项

  • 约定俗成:一旦元素添加到 TreeSet 之后,禁止修改TreeSet中的元素值
  • 原因:修改完TreeSet中的对象后,TreeSe t不会重新调整该元素在树中的位置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值