Java刷题错题笔记-day05-集合(CopyOnWriterArrayList、HashMap)

1.CopyOnWriterArrayList是强一致性列表吗?

不是

CopyOnWriteArrayList 不提供强一致性主要是因为它的修改操作是在一个新的拷贝上进行的,而不是直接在原始数据结构上。这种设计决策带来了一些影响:

  1. 读取操作不阻塞: CopyOnWriteArrayList 的读取操作是在原始数组上进行的,无锁,而写入在原数组的拷贝上进行。因此,写入操作期间,读取操作不会被阻塞,允许并发读取。但这也意味着在写入操作完成之前,读取操作可能会看到旧的数据。
  2. 写入操作的延迟: 当有写入操作发生时,CopyOnWriteArrayList 会创建一个新的数组,并在上面执行修改。在这个过程中,其他线程可能仍然在引用旧的数组。因此,在写入操作完成之前,其他线程可能无法感知到最新的修改。

下面是简化的 CopyOnWriteArrayList 的部分关键代码,以便更好地理解:

public class CopyOnWriteArrayList<E> {private transient volatile Object[] array;// .../***写入操作/public boolean add(E element) {synchronized (this) {Object[] currentArray = array;//1.拷贝原数组Object[] newArray = Arrays.copyOf(currentArray, currentArray.length + 1);//2.在新副本上执行添加操作newArray[currentArray.length] = element;//3.将原数组引用指向新副本array = newArray;return true;}}// ...public E get(int index) {return (E) array[index];}// ...
}

add 方法中,修改是在一个新的数组上进行的。而 get 方法只是直接访问当前数组,没有加锁,因此可能在写入操作进行时看到旧的数组。这就是导致不强一致性的主要原因之一。

2.HashMap允许key为null吗?

允许

key为null时,key的hash值恒为0,元素将被存储在数组的第一个位置

public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}static final int hash(Object key) {int h;//key为null,hash恒为0return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)//hash为0,`tab[i = (n - 1) & hash])`为tab[0])tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))//新key也为null时,走到这。p=tab[0],然后将p值赋予ee = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {//...省略代码}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)//新value替换旧valuee.value = value;afterNodeAccess(e);return oldValue;}}
}

3.HashSet允许有null值吗?

允许

因为HashSet是基于HashMap实现的,HashMap允许key为null

  • HashSet 是基于哈希表的集合,它不允许重复元素。
  • 当你向 HashSet 中添加元素时,实际上是将这个元素作为键存储在一个 HashMap 实例中,而值则是一个常量 PRESENT

以下是简化的 HashSet 类的一部分关键代码,以说明其是如何基于 HashMap 实现的:

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {// 用于存储元素的 HashMapprivate transient HashMap<E, Object> map;// 一个常量对象,作为所有元素的值private static final Object PRESENT = new Object();// 构造方法public HashSet() {map = new HashMap<>();}// 添加元素的方法public boolean add(E e) {return map.put(e, PRESENT) == null;}// 其他方法...
}

在上述代码中,

  • HashSet 的构造方法初始化了一个 HashMap 实例,
  • add 方法实际上是调用 HashMapput 方法来将元素作为键存储在 HashMap 中,将 PRESENT 作为相应的值。

因此,可以说 HashSet 是通过在 HashMap 的基础上添加一些包装来实现的。这种基于哈希表的实现提供了快速的插入和查询操作,并确保集合中的元素是唯一的。

4.JDK8 HashMap为啥不直接用红黑树?

1.红黑树(TreeNode)占用更大的内存,大约是常规节点(Node )的两倍内存大小
2.红黑树查询更快,当链表达到一定长度时链表查询变慢
所以不直接使用红黑树,等链表达到一定长度后再转换为红黑树结构

TreeNodeNode 分别是 HashMap 中两种不同的节点类型,用于表示哈希表中的元素。

  1. Node 节点:

    • Node 是基本的链表节点,用于处理哈希冲突时形成的链表。
    • Node 的结构相对简单,包含了键、值、哈希码和指向下一个节点的引用。
    static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}// ...
    }
    
  2. TreeNode 节点:

    • TreeNode 是红黑树节点,用于处理链表转化为红黑树时的节点。
    • TreeNode 的结构相对复杂,包含了键、值、哈希码、指向父节点、左子节点、右子节点的引用,以及颜色信息用于红黑树平衡。
    static final class TreeNode<K,V> extends Node<K,V> {TreeNode<K,V> parent;  // 父节点TreeNode<K,V> left;    // 左子节点TreeNode<K,V> right;   // 右子节点TreeNode<K,V> prev;    // 用于双向链表的前一个节点boolean red;           // 红黑树中的颜色标记// 构造方法TreeNode(int hash, K key, V val, Node<K,V> next) {super(hash, key, val, next);}// ...
    }
    

为什么 TreeNode 占用的内存更多但查询更快呢?

  • 占用内存更多: TreeNode 占用的内存更多主要是由于其包含了额外的红黑树结构信息,如父节点、左子节点、右子节点等。这些额外的信息使得每个节点的内存占用更大。

  • 查询更快: 红黑树的查询性能相对较好,因为红黑树是一种平衡二叉搜索树,保持了相对平衡的树结构。在红黑树中,查询操作的时间复杂度为 O(log N),而链表的查询操作的时间复杂度为 O(N)。所以,当链表转化为红黑树后,在具有大量哈希冲突的情况下,查询性能更好。红黑树的平衡性质确保了在最坏情况下的查询性能。

总的来说,TreeNode 占用更多内存但查询更快是通过引入红黑树结构来平衡在大型哈希冲突情况下的性能。在一般情况下,链表结构可能更为简单且更省内存。因此,HashMap 会在链表长度超过一定阈值时,将链表转换为红黑树,以提高在大规模哈希冲突情况下的性能。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zabbix的API调用

zabbix的API调用 资料参考&#xff1a;https://www.zabbix.com/documentation/4.0/zh/manual/api 看api文档就可以了&#xff0c;粘两个例子吧&#xff0c;如果配置了域名&#xff0c;可以请求域名 [rootnode ~]# vi zabbix_login.api curl -XPOST -H "Content-Type: ap…

探寻未来卫生新境界:互联网公厕是什么意思

近年来&#xff0c;科技的飞速发展深刻改变了我们生活的方方面面&#xff0c;而公共卫生领域也在这场变革中迎来了一场前所未有的革命。在这个新时代&#xff0c;一个备受瞩目的概念逐渐崭露头角——那就是“互联网公厕”。这究竟意味着什么&#xff1f;是一场卫生革新的崛起&a…

动手学深度学习4 线性代数

动手学深度学习4 线性代数 1. 线性代数--数学意义2. 线性代数的实现3. 按特定轴求和4. 线性代数QA 1. 线性代数–数学意义 视频&#xff1a;https://www.bilibili.com/video/BV1eK4y1U7Qy/?spm_id_fromautoNext&vd_sourceeb04c9a33e87ceba9c9a2e5f09752ef8 课件&#xff…

Protobuf 反射技术简介

对于反射大家应该不会陌生&#xff0c;如果你接触过一些框架&#xff08;如 ORM、IOC、OSGi 等&#xff09; 的内部实现&#xff0c;应该更能体会反射技术的应用可谓无处不在。 反射概念最早出现于人工智能领域&#xff0c;20 世纪 70 年代末被引入到程序语言设计中。1982 年 …

swaggerUI不好用,试试这个openapiUI?

title: swaggerUI不好用&#xff0c;试试这个openapiUI? date: 2024-01-08 categories: [tool] tags: [openapi,工具] description: 基于swaggger2, openapi3规范的UI文档 1.背景 由于长期使用 swaggerUI 工具&#xff0c;它的轻量风格个人觉得还是不错的&#xff0c;但是它…

【漏洞复现】Hikvision SPON IP网络对讲广播系统存在命令执行漏洞CVE-2023-6895

漏洞描述 Hikvision Intercom Broadcasting System是中国海康威视(Hikvision)公司的一个对讲广播系统。 Hikvision Intercom Broadcasting System是中国海康威视(Hikvision)公司的一个对讲广播系统。Hikvision Intercom Broadcasting System 3.0.3_20201113_RELEASE(HIK)版…

vulhub中的Apache SSI 远程命令执行漏洞

Apache SSI 远程命令执行漏洞 1.cd到ssi-rce cd /opt/vulhub/httpd/ssi-rce/ 2.执行docker-compose up -d docker-compose up -d 3.查看靶场是否开启成功 dooker ps 拉取成功了 4.访问url 这里已经执行成功了&#xff0c;注意这里需要加入/upload.php 5.写入一句话木马 &…

微信预约小程序制作指南:从小白到专家

在当今的数字时代&#xff0c;微信小程序已经成为了一种非常流行的应用方式。预约功能更是成为了许多小程序的核心功能之一。如果你也想为你的小程序添加预约功能&#xff0c;以下步骤将会对你有所帮助。 一、进入乔拓云网后台 乔拓云网是一个在线小程序开发平台&#xff0c;你…

golang指针介绍

前言 简单记录下&#xff0c;GO语言中的指针类型和值类型的使用&#xff0c;以及二两之前的区别 目录 前言指针类型介绍值类型和指针类型的使用区别值类型&#xff08;Value Types&#xff09;&#xff1a;指针类型&#xff08;Pointer Types&#xff09;&#xff1a;示例&…

如何使用Docker部署开源CMF Drupal并结合cpolar内网穿透远程访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

【软考中级-软件设计师】day4:数据结构-线性表、单链表、栈和队列、串

大纲 线性结构 顺序存储和链式存储区别 单链表的插入和删除 真题 栈和队列 真题 串

kubectlkubeletrancherhelmkubeadm这几个命令行工具是什么关系?

背景 在最近学习k8s的过程中&#xff0c;发现kubectl&kubelet&rancher&helm&kubeadm这几个命令怎么在交错使用&#xff0c;他们究竟是什么关系&#xff1f;他们分别应该在什么情况下使用呢&#xff1f;这里我进行了简单的总结&#xff0c;做个区分。 各工具说…

性能分析与调优: Linux 实现 缺页剖析与火焰图

目录 一、实验 1.环境 2.缺页(RSS增长)剖析与火焰图 一、实验 1.环境 &#xff08;1&#xff09;主机 表1-1 主机 主机架构组件IP备注prometheus 监测 系统 prometheus、node_exporter 192.168.204.18grafana监测GUIgrafana192.168.204.19agent 监测 主机 node_exporter…

实现锚点定位功能(React/Vue)

前言 最近接到一个需求&#xff0c;修改某某页面&#xff0c;增加XXX功能&#xff0c;并实现个锚点功能。做产品就是不断优化&#xff0c;增加功能的过程。实现锚点的方式很多&#xff0c; 很多UI库也提供了组件&#xff0c;可以根据自己的需求调整一下组件库也可以实现&#…

vulhub中的Apache HTTPD 换行解析漏洞(CVE-2017-15715)详解

Apache HTTPD 换行解析漏洞&#xff08;CVE-2017-15715&#xff09; 1.cd到CVE-2017-15715 cd vulhub/httpd/CVE-2017-15715 2.运行docker-compose build docker-compose build 3.运行docker-compose up -d 4.查看docker-compose ps 5.访问 出现这个表示安装成功 6.漏洞复现…

C 练习实例22

题目&#xff1a;两个乒乓球队进行比赛&#xff0c;各出三人。甲队为a,b,c三人&#xff0c;乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比&#xff0c;c说他不和x,z比&#xff0c;请编程序找出三队赛手的名单。 首先吐槽一下&#xff0c;这是…

Linux系统操作命令

Linux管理 在线查询Linux命令&#xff1a; https://www.runoob.com/linux/linux-install.htmlhttps://www.linuxcool.com/https://man.linuxde.net/ 1.Linux系统目录结构 Linux系统的目录结构是一个树状结构&#xff0c;每一个文件或目录都从根目录开始&#xff0c;并且根目…

MySQL语法练习-DML语法练习

文章目录 0、相关文章1、添加数据2、修改数据3、删除数据4、总结 0、相关文章 《MySQL练习-DDL语法练习》 1、添加数据 # 给指定字段添加数据 insert into 表名 (字段名1,字段名2,...) values(值1,值2...);# 给全部字段添加数据 insert into 表名 values(值1,值2,...);#批量…

五种主流数据库:字符串匹配

当我们不能完全确定需要查找的信息时&#xff0c;可以使用 SQL 模糊查找的功能进行文本检索&#xff0c;对应的运算符是 LIKE。 本文比较五种主流数据库对于文本模糊查找的实现和差异&#xff0c;包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。 字符串模糊匹配My…

C++入门【24-C++ 传递指针给函数】

C 允许您传递指针给函数&#xff0c;只需要简单地声明函数参数为指针类型即可。 下面的实例中&#xff0c;我们传递一个无符号的 long 型指针给函数&#xff0c;并在函数内改变这个值&#xff1a; 实例 #include <iostream>#include <ctime>using namespace std…