Java学习笔记(19)

双列集合

键值对 一一对应

键值对对象 entry

Map

Put第一次给不存在的key,会把键值对添加到map中,返回null

Put给同一个key是会覆盖value的,返回被覆盖的值value

Remove根据key删除键值对,返回被删除的值value

Map遍历

键找值

把所有键放到单列集合中map.keyset()方法,获取每一个键,再调用map.get(key)获取每一个值

键值对

Map.entryset()获得每一键值对,放到一个set集合中

Map.Entry<string,string>:因为Entry是Map里的一个接口,所以在用Entry接口的时候,要用Map调用

Entry.getkey()  Entry.getvalue() 分别获取key和value

Lambda遍历

Foreach

写一个匿名内部类实现biconsumer接口,创建这个匿名内部类的对象

Hashmap

但是计算哈希值的时候,只会利用键计算哈希值,和值无关

键是自定义对象,要重写hashcode和equals方法,值的话就不用

package exercise;

import java.util.*;

public class exercise3 {
    public static void main(String[] args) {
        String[] arr = {"A", "B", "C", "D"};
        ArrayList<String> list = new ArrayList<>();
        Random r = new Random();
        for (int i = 0; i < 80; i++) {
            list.add(arr[r.nextInt(arr.length)]);
        }

        HashMap<String,Integer> hm = new HashMap<>();
        for (String s : list) {
            if (hm.containsKey(s)) {
                Integer i = hm.get(s);
                i++;
                hm.put(s, i);
            } else {
                hm.put(s, 1);
            }
        }

        System.out.println(hm);

        //求最大值
        int max = 0;
        Set<Map.Entry<String, Integer>> entries = hm.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            if (entry.getValue() > max) {
                max = entry.getValue();
            }
        }
        
        //把和最大值相同的景点打印
        for (Map.Entry<String, Integer> entry : entries) {
            if (entry.getValue() == max) {
                System.out.println(entry.getKey());
            }
        }

    }
}

Linkedhashmap

Treemap

按照键进行排序

package exercise;

import java.util.TreeMap;

public class exercise4 {
    public static void main(String[] args) {
        String str = "aababcabcdabcde";
        TreeMap<Character, Integer> ts = new TreeMap<>();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (ts.containsKey(c)) {
                Integer j = ts.get(c);
                j++;
                ts.put(c, j);
            } else {
                ts.put(c, 1);
            }
        }

        StringBuilder sb = new StringBuilder();
        ts.forEach((character, integer) -> sb.append(character).append(" (").append(integer).append(") "));
        System.out.print(sb);
    }
}

Hashmap的底层源码

→:是继承自Map的方法

↑:重写Map里的方法

m:是方法(同名就是构造方法,不同名就是成员方法)

f:是成员属性,可能是变量或常量

i:接口

c:内部类

Hashmap中每一个元素都是Node对象,实现entry接口

Hash:记录哈希值

Key:键

Value:值

Next:记录下一个node的地址值

Hashmap中的红黑树

Parent:父节点

Left:左子结点

Right:右子节点

Red:ture就是红色,false就是黑

Table:记录数组的地址值,装的就是每一个node对象

默认数组初始容量16

默认加载因子0.75

Hashmap最大容量2^30

Hashmap在调用空参构造的时候,底层的数组还没有创建,默认null

只是指定了加载因子为0.75

直到put的时候才真正建立数组

Hash(key):根据键计算出哈希值

onlyifAbsent:当前的数据是否保留,false就是不保留(当新的元素添加,键相同时,值就会覆盖掉原来的)

Hashmap添加元素源码分析

Hashmap添加第一个元素

数组位置为null

Putval

Resize():第一次添加元素,就会在这个方法里创建新的数组

第二种情况

数组位置不为null,键不重复,挂在下面形成链表或者红黑树

第三种情况

数组位置不为null,键重复,元素覆盖

这里会直接break

走这里

把新元素的值赋值给老元素的键值对的值

Treemap源码

添加第一个元素

//表示两个元素的键比较之后的结果

    int cmp;

//表示当前要添加节点的父节点

    Entry<K,V> parent;

//表示当前的比较规则

//如果我们是采取默认的自然排序,那么此时comparator记录的是null,cpr记录的也是null

//如果我们是采取比较去排序方式,那么此时comparator记录的是就是比较器

    Comparator<? super K> cpr = comparator;

//表示判断当前是否有比较器对象

//如果传递了比较器对象,就执行if里面的代码,此时以比较器的规则为准

//如果没有传递比较器对象,就执行else里面的代码,此时以自然排序的规则为准

    if (cpr != null) {

        do {

            parent = t;

            cmp = cpr.compare(key, t.key);

            if (cmp < 0)

                t = t.left;

            else if (cmp > 0)

                t = t.right;

            else {

                V oldValue = t.value;

                if (replaceOld || oldValue == null) {

                    t.value = value;

                }

                return oldValue;

            }

        } while (t != null);

    } else {

//把键进行强转,强转成Comparable类型的

//要求:键必须要实现Comparable接口,如果没有实现这个接口

//此时在强转的时候,就会报错。

        Comparable<? super K> k = (Comparable<? super K>) key;

        do {

//把根节点当做当前节点的父节点

            parent = t;

//调用compareTo方法,比较根节点和当前要添加节点的大小关系

            cmp = k.compareTo(t.key);

            if (cmp < 0)

//如果比较的结果为负数

//那么继续到根节点的左边去找

                t = t.left;

            else if (cmp > 0)

//如果比较的结果为正数

//那么继续到根节点的右边去找

                t = t.right;

            else {

//如果比较的结果为0,会覆盖

                V oldValue = t.value;

                if (replaceOld || oldValue == null) {

                    t.value = value;

                }

                return oldValue;

            }

        } while (t != null);

    }

//就会把当前节点按照指定的规则进行添加

    addEntry(key, value, parent, cmp < 0);

return null;

 private void addEntry(K key, V value, Entry<K, V> parent, boolean addToLeft) {

    Entry<K,V> e = new Entry<>(key, value, parent);

    if (addToLeft)

        parent.left = e;

    else

        parent.right = e;

//添加完毕之后,需要按照红黑树的规则进行调整

    fixAfterInsertion(e);

    size++;

    modCount++;

}

private void fixAfterInsertion(Entry<K,V> x) {

//因为红黑树的节点默认就是红色的

    x.color = RED;

//按照红黑规则进行调整

//parentOf:获取x的父节点

//parentOf(parentOf(x)):获取x的爷爷节点

//leftOf:获取左子节点

    while (x != null && x != root && x.parent.color == RED) {

//判断当前节点的父节点是爷爷节点的左子节点还是右子节点

//目的:为了获取当前节点的叔叔节点

        if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {

//表示当前节点的父节点是爷爷节点的左子节点

//那么下面就可以用rightOf获取到当前节点的叔叔节点

            Entry<K,V> y = rightOf(parentOf(parentOf(x)));

            if (colorOf(y) == RED) {

//叔叔节点为红色的处理方案

//把父节点设置为黑色

                setColor(parentOf(x), BLACK);

//把叔叔节点设置为黑色

                setColor(y, BLACK);

//把爷爷节点设置为红色

                setColor(parentOf(parentOf(x)), RED);

//把爷爷节点设置为当前节点

                x = parentOf(parentOf(x));

            } else {

//叔叔节点为黑色的处理方案

//表示判断当前节点是否为父节点的右子节点

                if (x == rightOf(parentOf(x))) {

//表示当前节点是父节点的右子节点

                    x = parentOf(x);

//左旋

                    rotateLeft(x);

                }

                setColor(parentOf(x), BLACK);

                setColor(parentOf(parentOf(x)), RED);

                rotateRight(parentOf(parentOf(x)));

            }

        } else {

//表示当前节点的父节点是爷爷节点的右子节点

//那么下面就可以用leftOf获取到当前节点的叔叔节点

            Entry<K,V> y = leftOf(parentOf(parentOf(x)));

            if (colorOf(y) == RED) {

                setColor(parentOf(x), BLACK);

                setColor(y, BLACK);

                setColor(parentOf(parentOf(x)), RED);

                x = parentOf(parentOf(x));

            } else {

                if (x == leftOf(parentOf(x))) {

                    x = parentOf(x);

                    rotateRight(x);

                }

                setColor(parentOf(x), BLACK);

                setColor(parentOf(parentOf(x)), RED);

                rotateLeft(parentOf(parentOf(x)));

            }

        }

    }

//把根节点设置为黑色

    root.color = BLACK;

}

**************************

6.课堂思考问题:

6.1TreeMap添加元素的时候,键是否需要重写hashCode和equals方法?

此时是不需要重写的。

6.2HashMap是哈希表结构的,JDK8开始由数组,链表,红黑树组成的。

既然有红黑树,HashMap的键是否需要实现Compareable接口或者传递比较器对象呢?

不需要的。

因为在HashMap的底层,默认是利用哈希值的大小关系来创建红黑树的

6.3TreeMap和HashMap谁的效率更高?

如果是最坏情况,添加了8个元素,这8个元素形成了链表,此时TreeMap的效率要更高

但是这种情况出现的几率非常的少。

一般而言,还是HashMap的效率要更高。

6.4你觉得在Map集合中,java会提供一个如果键重复了,不会覆盖的put方法呢?

此时putIfAbsent本身不重要。

传递一个思想:

代码中的逻辑都有两面性,如果我们只知道了其中的A面,而且代码中还发现了有变量可以控制两面性的发生。

那么该逻辑一定会有B面。

习惯:

boolean类型的变量控制,一般只有AB两面,因为boolean只有两个值

int类型的变量控制,一般至少有三面,因为int可以取多个值。

6.5三种双列集合,以后如何选择?

HashMap LinkedHashMap TreeMap

默认:HashMap(效率最高)

如果要保证存取有序:LinkedHashMap

如果要进行排序:TreeMap

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/476333.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python语法踩坑 | list的append操作如何从in-place改为out-of-place

背景 博主写python遇到一个问题&#xff0c;需要把对list添加元素改为非原地操作&#xff0c;即不修改原list。 但是由于列表中的元素是字典类型&#xff0c;无法直接用运算符。 于是写出了下面这行代码 query_list message_list.copy().append(one_question) 其中message…

Anaconda安装 (windowsLinux)

文章目录 Anaconda简介设置国内源pip || conda 一、Anaconda &#xff08;Windows系统&#xff09;1.1 下载及安装1.2 虚拟环境创建1.3 在Pycharm中配置conda的环境 二、Anaconda&#xff08;Linux系统&#xff09; Anaconda简介 conda是一个开源的包、环境管理器&#xff0c;可…

探索 Atlassian 云平台:组织、站点、产品架构解析

我们通常访问的是 Atlassian 的某个云站点&#xff0c;比如填空题-中国站点为&#xff1a;cloze-cn.atlassian.net。当我们访问该站点内的具体产品时&#xff0c;只需在该站点的 URL 后添加相应产品的缩写&#xff0c;例如&#xff1a; Confluence: cloze-cn.atlassian.net/wi…

12.电子产品拆解分析-LED T8_16W灯管

12.电子产品拆解分析~LED_T8_16W家用灯管 一、功能介绍二、电路分析以及器件作用一、功能介绍 ①无需使用镇流器(启辉器),只需接到220V即可点亮使用;②节能省电 透光性强 无可视频闪;二、电路分析以及器件作用 220V交流电经过MB10F桥式整流出300V脉动直流电,然后经过6.8u…

某J 集成 cas5.3res api登录

在学习一个开源项目是时集成了cas&#xff0c;但文档过于简单&#xff0c;研究了两天这次记录做个补充 1.下载cas项目 GitHub - apereo/cas-overlay-template at 5.3 2.编译 解压zip&#xff0c;命令行进去&#xff0c;执行mvn clean package 结束之后会出现 target 文件夹&…

Android14 - Framework- Configuration的创建和更新

本文描述从启动一个新进程的Activity起&#xff0c;Framwork层Configuration的创建和传导过程。 首先&#xff0c;我们知道所有的Window容器都继承于WindowContainer&#xff0c;而WindowContainer本身是ConfigurationContainer的子类。于此同时&#xff0c;WindowProcessContr…

[NOIP1998 提高组] 拼数

[NOIP1998 提高组] 拼数 题目描述 设有 n n n 个正整数 a 1 … a n a_1 \dots a_n a1​…an​&#xff0c;将它们联接成一排&#xff0c;相邻数字首尾相接&#xff0c;组成一个最大的整数。 输入格式 第一行有一个整数&#xff0c;表示数字个数 n n n。 第二行有 n n …

【Vue3遇见的问题】创建vue3的项目使用vscode打开后项目的app.vue里面存在爆红

出现的问题 直接上上问题:问题的图片如下: 解决方法 解决效果 补充 因为vetur的插件禁用了 所以需要一个新插件来 这里发现的官网推荐的插件 也就是volar 他两是一样的

各位老板,你需要的工厂数字孪生可视化库在这

各位老板是不是很喜欢下面这种有逼格的大屏,下面介绍一下怎么实现的,保证有所收获。 Cesium是一个开源的WebGL JavaScript库&#xff0c;用于创建高性能的三维地球、地图和虚拟环境。它支持在浏览器中实现高质量的地球模拟&#xff0c;同时提供了丰富的功能特点&#xff0c;使得…

【Linux进程的状态】

目录 看Linux源码中的说法 如何查看进程状态&#xff1f; 各个状态的关系 僵尸进程 举个栗子 现象 僵尸进程的危害 孤儿进程 举个栗子 现象 进程的优先级 基本概念 为什么要有进程优先级&#xff1f; 查看系统进程 进程的大致属性 进程优先级vs进程的权限 Linu…

AI基础知识(4)--贝叶斯分类器

1.什么是贝叶斯判定准则&#xff08;Bayes decision rule&#xff09;&#xff1f;什么是贝叶斯最优分类器&#xff08;Bayes optimal classifier&#xff09;&#xff1f; 贝叶斯判定准则&#xff1a;为最小化总体风险&#xff0c;只需在每个样本上选择那个能使条件风险最小的…

用 Open-Sora 高效创作视频,让创意触手可及

近年来&#xff0c;视频内容以爆炸式增长席卷了我们的生活。从短视频平台到直播带货&#xff0c;视频正成为人们获取信息和娱乐的主要方式。然而&#xff0c;传统视频制作流程往往耗时费力&#xff0c;对于普通用户来说门槛较高。 为了降低视频创作门槛&#xff0c;让更多人享…

Git的 .gitignore文件及标签使用

Git的 .gitignore文件及标签使用 什么是.gitignoregit check-ignore -v 文件名 查看.gitignore里面什么内容忽略了该文件 git add -f [filename] 强制添加把指定文件排除在 .gitignore 规则外的写法给命令配置别名标签创建标签git tag [name] 创建标签git tag 列出所有标签git …

RESNET的复现pytorch版本

RESNET的复现pytorch版本 使用的数据为Object_102_CaDataset&#xff0c;可以在网上下载&#xff0c;也可以在评论区问。 RESNET模型的亮点 1.提出了残差模块。 2.使用Batch Normalization加速训练 3.残差网络&#xff1a;易于收敛&#xff0c;很好的解决了退化问题&#…

真实数据!一张切片实现101种蛋白的超多重空间单细胞原位成像

头颈鳞状细胞癌 (HNSCC) 是第七大常见癌症。免疫检查点抑制剂 (ICIs) 在治疗复发/转移病例方面显示出良好前景&#xff0c;约30%的患者可获得持久获益。但是目前反映HNSCC肿瘤微环境 (TME) 特征的生物标志物有限&#xff0c;需要更深入的组织表征分析。因此&#xff0c;需要新的…

linux查看cpu/内存/磁盘利用率

1、cpu 命令&#xff1a; top 2、内存 命令&#xff1a; free -h 3、磁盘 命令&#xff1a; df -h

《操作系统真相还原》读书笔记九:用c编写内核

用c语言先编写一个死循环 main.c int main(void) {while(1);return 0; }编译该文件 gcc -c -o main.o main.c-- Ttext参数表示起始虚拟地址为0xc0001500 -e参数表示程序入口地址 ld main.o -Ttext 0xc0001500 -e main -o kernel.bin-- 将kernel.bin写入第9个扇区 dd if/ho…

十九、网络编程

目录 一、什么是网络编程二、网络编程三要素2.1 IP2.2 InetAddress的使用2.3 端口号2.4 协议 三、UDP通信程序3.1 发送数据3.2 接收数据3.3 练习 四、UDP的三种通信方式五、TCP的通信程序六、三次握手和四次挥手七、练习7.1 TCP通信练习1——多发多收7.2 TCP通信练习2——接收和…

Cookie使用

文章目录 一、Cookie基本使用1、发送Cookie2、获取Cookie 二、Cookie原理三、Cookie使用细节 一、Cookie基本使用 1、发送Cookie package com.itheima.web.cookie;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.I…

82.删除排序链表中的重复元素II

给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,5]示例 2&#xff1a; 输入&#xff1a;head [1,1,1,2…
最新文章