黑马day07-Set集合、Map集合

本文详细介绍了Java集合框架中的Set系列,包括HashSet、LinkedHashSet和TreeSet的底层实现原理,如哈希表、链表和红黑树。讨论了对象哈希值的特点,以及如何通过重写hashCode和equals方法实现自定义类型的去重。此外,还涵盖了Map集合的概念、常用方法以及遍历策略,强调了并发修改异常的问题和双列集合的特点。
摘要由CSDN通过智能技术生成

目录

Set集合

Set系列集合特点:

HashSet集合的底层原理:

哈希值:

对象哈希值的特点:

HashSet底层

了解一下数据结构(树)

普通二叉树

二叉查找树(二叉排序树)

平衡二叉树(也是二叉查找树)

红黑树

小结:

深入理解HashSet集合的去重机制

总结:

LinkedHashSet底层原理

总结

TreeSet

特点:

注意:

TreeSet自定义排序规则

注意事项:集合的并发修改异常问题

集合进阶(二)

Collection类的其他相关知识

前置知识:可变参数

Collections类

Map集合

概念

Map集合在什么业务场景下使用

Map集合体系

Map集合体系的特点

总结:

常用方法

为什么要先学习Map的常用方法

Map常用方法

遍历方式

1.键找值

2.键值对

3.Lambda


Set集合

Set系列集合特点:

无序∶添加数据的顺序和获取出的数据顺序不一致;不重复;无索引;

HashSet:无序,不重复,无索引

LinkedHashSet:有序,不重复,无索引

TreeSet:排序,不重复,无索引

HashSet集合的底层原理:

注意:在正式了解HashSet集合的底层原理前,我们需要先搞清楚一个前置知识:哈希值!

哈希值:

就是一个int类型的数值,Java中每个对象都有一个哈希值,可以认为是对象的一个身份证编号。

Java中的所有对象,都可以调用Obejct类提供的hashCode方法,返回该对象自己的哈希值。

对象哈希值的特点:

同一个对象多次调用hashCode()方法返回的哈希值是相同的。

不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞)。

HashSet底层

基于哈希表实现

哈希表是一种增删改查数据,性能都较好的数据结构

JDK8之前HashSet集合的底层原理,基于哈希表:数组+链表

JDK8开始HashSet集合的底层原理,基于哈希表:数组+链表+红黑树

了解一下数据结构(树)

普通二叉树

度:每一个节点的子节点数量

二叉树中,任意节点的度<=2

树高:树的总层数

根节点:最顶层的节点

左子节点

右子节点

左子树

右子树

二叉查找树(二叉排序树)

规则:

小的存左边

大的存右边

一样的不存

二叉查找树存在的问题:

链化

当数据已经是排好序的,导致查询的性能与单链表一样,查询速度变慢!

平衡二叉树(也是二叉查找树)

在满足查找二叉树的大小规则下,让树尽可能矮小,以此提高查数据的性能。

红黑树

红黑树,就是可以自平衡的二叉查找树

小结:

小结:JDK8开始后,哈希表中引入了红黑树后,进一步提高了操作数据的性能。

深入理解HashSet集合的去重机制

HashSet集合默认不能对内容一样的两个不同对象去重复!

如何让HashSet集合能够实现对内容一样的两个不同对象也能去重复?

/**
 * 目标:自定义的类型的对象,比如两个内容一样的学生对象,如果让HashSet集合能够去重复!
 *
 * 当集合底层结构是哈希表结构,要想让存储的自定义类型对象能够去重,就得对类型进行重写hashCold和equals。
 */
public class SetTest3 {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<>();
        students.add(new Student("张三", 18, 180));
        students.add(new Student("张三", 18, 180));


        System.out.println("students = " + students);
        /*
        没有重写HashCode和equals方法之前
            students = [Student{name='张三', age=18, height=180.0}, Student{name='张三', age=18, height=180.0}]
            为什呢
                new了两个对象,每个对象的hashCode近似于地址, hash值不同,进一步对数组长度取余运算,得到的位置也不同。两个都会存储下来。
                即便是不同的哈希值,取余运算得到的是相同的位置,也会进一步比较equals,此时的equals方法还没有重写,默认比较的是真是的地址是否相同

            如果想要达到同类型的不同对象,当属性值都相同是,然后就能够起到去重的效果,就需要重写hashCode和equals方法
         */



    }
}

总结:

LinkedHashSet底层原理

依然是基于哈希表(数组,链表,红黑树)实现的

但是,他的每个元素都额外多了一个双链表的机制记录它前后元素的位置。

/**
 * @author HuanLe
 * @version 1.0
 *
 * LinkedHashSet的特点:有序,去重,无索引
 * 有序:双链表决定
 * 去重:哈希表决定
 *
 * 重点记住特点,用法和Collection一样
 */
public class SetLinkedHashSet {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("AAA");
        linkedHashSet.add("AAA");
        linkedHashSet.add("BBB");
        linkedHashSet.add("CCC");

        System.out.println("linkedHashSet = " + linkedHashSet);
    }
}

总结

TreeSet

特点:

不重复、无索引、可排序(默认升序排序,按照元素的大小,由小到大排序)

底层是基于红黑树实现的排序。

注意:

对于数值类型:Integer , Double,默认按照数值本身的大小进行升序排序。

对于字符串类型︰默认按照首字符的编号升序排序。

TreeSet自定义排序规则

注意:如果类本身有实现Compaable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。

总结:

注意事项:集合的并发修改异常问题

使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。

由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常的错误

集合进阶(二)

Collection类的其他相关知识

前置知识:可变参数

就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型...参数名称;

可变参数的特点和好处

特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。

好处:常常用来灵活的接收数据。

可变参数的注意事项:

可变参数在方法内部就是一个数组。

一个形参列表中可变参数只能有一个

可变参数必须放在形参列表的最后面

public class ParamTest {
    public static void main(String[] args) {
        add();
        add(1);
        add(1, 2);
        //可变参数的底层本质上是数组,可以直接传入数组
        add(new int[]{1, 2, 3, 4});
        add(1, 2, 3, 4);

    }

    /*public static void add(int a) {

}
public static void add(int a, int b) {

}*/

    public static void add(int... a) {
        //使用方式:直接遍历即可,因为本质就是数组
        int sum = 0;
        for (int e : a) {
            sum += e;
        }
        System.out.println("sum = " + sum);
    }

    //可变参数在方法中可以有几个? 1个
    //因为可变参数必须要在列表中的最后位置
    /*public static void add(int a, int... b, String... c) {

}*/
}

Collections类

是一个用来操作集合的工作类

Collections只能支持对list集合进行排序

注意:

本方法可以直接对自定义类型的List集合排序,但自定义类型必须实现了Comparable接口,指定了比较规则才可以

Map集合

认识Map集合

概念

Map集合称为双列集合,格式:{key1=value1 , key2=value2 , key3=value3 ,...,}一次需要存一对数据做为一个元素.

Map集合的每个元素"“key=value"称为一个键值对/键值对对象/一个Entry对象,Map集合也被叫做"键值对集合"

Map集合的所有键是不允许重复的,但值可以重复,键和值是——对应的,每一个键只能找到自己对应的值

Map集合在什么业务场景下使用

Map集合体系

Map集合体系的特点

注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的

HashMap (由键决定特点):无序、不重复、无索引;(用的最多)

LinkedHashMap(由键决定特点):由键决定的特点︰有序、不重复、无索引。

TreeMap(由键决定特点):按照大小默认升序排序、不重复、无索引。

总结:

常用方法

为什么要先学习Map的常用方法

Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的。

Map常用方法

public class MapTest2API {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();

        // 1.public V put(K v,V v) 添加元素: 无序,不重复,无索引。
        //put拥有添加和修改的能力
        //返回值:如果第一次put键值对数据,返回null,如果见是存在的再次put,返回的就是原来键所对应的值
        map.put("王宝强", "马蓉");
        map.put("宋喆", "马蓉");
        map.put("王宝强", "翠花");

        System.out.println("map = " + map);
        map.put("贾乃亮", "李小璐");
        map.put("PGOne", "李小璐");


        // 2.public int size():获取集合的大小
        System.out.println("map.size() = " + map.size());

        // 3、public void clear():清空集合
//        map.clear();

        // 4.public boolean isEmpty(): 判断集合是否为空,为空返回true ,反之!
        System.out.println("map.isEmpty() = " + map.isEmpty());


        // 5.public V get(Object key):根据键获取对应值
        String value = map.get("贾乃亮");
        System.out.println("value = " + value);

        // 6. public V remove(Object key):根据键删除整个元素(删除键会返回键的值)
        String remove = map.remove("王宝强");
        System.out.println("remove = " + remove);
        System.out.println("map = " + map);

        // 7.public  boolean containsKey(Object key): 判断是否包含某个键 ,包含返回true ,反之
        boolean containsKey = map.containsKey("奥特曼");
        System.out.println("containsKey = " + containsKey);

        // 8.public boolean containsValue(Object value): 判断是否包含某个值。
        System.out.println("map.containsValue(\"李小璐\") = " + map.containsValue("李小璐"));


        // 9.public Set<K> keySet(): 获取Map集合的全部键。
        Set<String> keys = map.keySet();
        System.out.println("keys = " + keys);

        // 10.public Collection<V> values(); 获取Map集合的全部值。
        Collection<String> values = map.values();
        System.out.println("values = " + values);

        // 11.把其他Map集合的数据倒入到自己集合中来。(拓展)
        HashMap<String, String> names = new HashMap<>();
        names.putAll(map);
        System.out.println("names = " + names);
    }
}

遍历方式

1.键找值

public static void main(String[] args) {
        // 准备一个Map集合。
        Map<String, Double> map = new HashMap<>();
        map.put("蜘蛛精", 162.5);
        map.put("蜘蛛精", 169.8);
        map.put("紫霞", 165.8);
        map.put("至尊宝", 169.5);
        map.put("牛魔王", 183.6);
        System.out.println(map);

        // 1、获取Map集合的全部键
        Set<String> keys = map.keySet();
        
        // 2、遍历全部的键,根据键获取其对应的值
        for (String key : keys) {
            Double val = map.get(key);
            System.out.println("val = " + val);
        }


    }

2.键值对

public static void main(String[] args) {
        Map<String, Double> map = new HashMap<>();
        map.put("蜘蛛精", 169.8);
        map.put("紫霞", 165.8);
        map.put("至尊宝", 169.5);
        map.put("牛魔王", 183.6);
        System.out.println(map);

        // 1、调用Map集合提供entrySet方法,把Map集合转换成键值对类型的Set集合

        //调用entrySet
        Set<Map.Entry<String, Double>> entrySet = map.entrySet();

        //遍历
        for (Map.Entry<String, Double> entry : entrySet) {
            String key = entry.getKey();
            Double value = entry.getValue();
            System.out.println(key + ":" + value);
        }
    }

3.Lambda

/**
 * 目标:掌握Map集合的第三种遍历方式:forEach方法遍历【Lambda】。
 */
public class MapTest3 {
    public static void main(String[] args) {
        Map<String, Double> map = new HashMap<>();
        map.put("蜘蛛精", 169.8);
        map.put("紫霞", 165.8);
        map.put("至尊宝", 169.5);
        map.put("牛魔王", 183.6);

        //匿名内部类方式
        map.forEach(new BiConsumer<String, Double>() {
            @Override
            public void accept(String s, Double aDouble) {
                System.out.println(s + " : " + aDouble);
            }
        });
        
        //Lambda方式
        map.forEach((k, v) -> {
            System.out.println(k + " : " + v);
        });

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值