增强day07-集合进阶(Set、Map集合)

  1. HashSet集合底层原理
    1. 底层基于哈希表实现
      1. JDK8以前:哈希表 = 数组 + 链表
      2. JDK8以后:哈希表 = 数组 + 链表 + 红黑树
    2. JDK8以前
      1. image.png
      2. 我们发现往HashSet集合中存储元素时,底层调用了元素的两个方法:一个是hashCode方法获取元素的hashCode值(哈希值);另一个是调用了元素的equals方法,用来比较新添加的元素和集合中已有的元素是否相同。
      3. 只有新添加元素的hashCode值和集合中以后元素的hashCode值相同、新添加的元素调用equals方法和集合中已有元素比较结果为true, 才认为元素重复。
      4. 如果hashCode值相同,equals比较不同,则以链表的形式连接在数组的同一个索引为位置(如上图所示)
    3. JDK8以后
      1. image.png
  2. HashSet去重原理
    1. 前提条件:在一个自定义类中如何实现去重呢?
    2. 我们知道HashSet用 hashcoded() 和 equals 方法来存储元素,如果我们重写这两个方法,让这两个方法依赖于自定义类的属性,如果两个实例的属性相等,那么就会被视为两个重复的实例,那么HashSet在存储的时候,就不会重复存入。
public class Student{
    private String name; //姓名
    private int age; //年龄
    private double height; //身高
 
    //无参数构造方法
    public Student(){}
    //全参数构造方法
    public Student(String name, int age, double height){
        this.name=name;
        this.age=age;
        this.height=height;
    }
    //...get、set、toString()方法自己补上..
    
    //按快捷键生成hashCode和equals方法
    //alt+insert 选择 hashCode and equals
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        if (Double.compare(student.height, height) != 0) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        temp = Double.doubleToLongBits(height);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}
  1. LinkedHashSet底层原理
    1. 底层基于哈希表实现的(数组 链表 红黑树)
    2. 但是存在双链表机制
    3. image.png
    4. 每次添加元素,就和上一个元素用双向链表连接一下。第一个添加的元素是双向链表的头节点,最后一个添加的元素是双向链表的尾节点。
  2. TreeSet集合
    1. 是一个基于红黑树的有序集合。
    2. 特点:可以对元素进行排序,但是必须指定元素的排序规则,即它可以按照元素的自然顺序或者通过提供的 Comparator 进行排序。
    3. 如果往集合中存储String类型的元素,或者Integer类型的元素,它们本身就具备排序规则,所以直接就可以排序。
    4. 如果往TreeSet集合中存储自定义类型的元素,比如说Student类型,则需要我们自己指定排序规则,否则会出现异常。此时运行代码,会直接报错。原因是TreeSet不知道按照什么条件对Student对象来排序。
    5. 我们想要告诉TreeSet集合按照指定的规则排序,有两种办法:
      1. 第一种:让元素的类实现Comparable接口,重写compareTo方法
      2. 第二种:在创建TreeSet集合时,通过构造方法传递Compartor比较器对象
  3. 并发修改异常
    1. 在使用迭代器遍历集合时,可能存在并发修改异常。
    2. 迭代器遍历机制,规定迭代器遍历集合的同时,不允许集合自己去增删元素,否则就会出现这个异常。
    3. 怎么解决这个问题呢?不使用集合的删除方法,而是使用迭代器的删除方法
//需求:找出集合中带"李"字的姓名,并从集合中删除
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String name = it.next();
    if(name.contains("李")){
        list.remove(name);
    }
}
System.out.println(list);

正确答案:
//需求:找出集合中带"李"字的姓名,并从集合中删除
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String name = it.next();
    if(name.contains("李")){
        //list.remove(name);
        it.remove(); //当前迭代器指向谁,就删除谁
    }
}
System.out.println(list);
  1. Map集合
    1. image.png
    2. image.png
    3. 遍历方式:
      1. 先获取map集合全部的键集合,然后遍历键来找值
      2. 获取map集合的entry对象集合,然后遍历这个集合来获得key value
      3. 方法:forEach(BiConsumer <K,V> action),结合lambda遍历Map集合
// 1、获取Map集合的全部键
        Set<String> keys = map.keySet();
        // System.out.println(keys);
        // [蜘蛛精, 牛魔王, 至尊宝, 紫霞]
        //         key
        // 2、遍历全部的键,根据键获取其对应的值
        for (String key : keys) {
            // 根据键获取对应的值
            double value = map.get(key);
            System.out.println(key + "=====>" + value);
        }

// 1、调用Map集合提供entrySet方法,把Map集合转换成键值对类型的Set集合
        Set<Map.Entry<String, Double>> entries = map.entrySet();
        for (Map.Entry<String, Double> entry : entries) {
            String key = entry.getKey();
            double value = entry.getValue();
            System.out.println(key + "---->" + value);
        }

//遍历map集合,传递匿名内部类
        map.forEach(new BiConsumer<String, Double>() {
            @Override
            public void accept(String k, Double v) {
                System.out.println(k + "---->" + v);
            }
        });
		//遍历map集合,传递Lambda表达式
        map.forEach(( k,  v) -> {
            System.out.println(k + "---->" + v);
        });
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值