当前位置: 首页 > news >正文

《数据解构》HashMap源码解读

👑作者主页:Java冰激凌
📖专栏链接:数据结构  

目录

了解HashMap

HashMap的构造

两个参数的构造方法

一个参数的构造方法  

不带参数的构造方法

哈希表初始化的长度

HashMap源码中的成员

Pt

Get


了解HashMap

 首先我们要明确 什么是HashMap? 

        HashMap 是一个用于存储(Key - Value)键值对的集合 每一个键值对也称为Entry ,这些键值对被均匀的分布在了一个存储的table数组当中 


本文讨论的HashMap是基于JDK8 的源码~

面试题

        HashMap底层的数据结构是什么?

        是一个特殊的数组 

        Hash表示什么?

        散列表  一个用于存储(Key - Value)键值对的集合 每一个键值对也称为Entry ,这些键值对被均匀的分布在了一个存储的table数组当中

HashMap的构造

HashMap的构造也是有多种形式的

两个参数的构造方法

//public HashMap (int,float)public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " +loadFactor);this.loadFactor = loadFactor;this.threshold = tableSizeFor(initialCapacity);}

这个构造方法 是传入两个参数 第一个参数为初始化哈希表的长度 第二个参数是手动指定负载因子

 我们着重来观察一下这个代码 我们进入方法 是非常有趣的

static final int tableSizeFor(int cap) {int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}

这个代码是干啥的呢? 写的花里胡哨的 可其实 这个可是非常有趣的 这个是我们传入的初始化的长度 这个方法会帮我们转换为2的最小次幂 我们来解读一下 举例我们传入cap为10

static final int tableSizeFor(int cap) {//cap = 10int n = cap - 1;// 9 00000000 00000000 00000000 00001001n |= n >>> 1;//n>>>1 00000000 00000000 00000000 00001100//n     00000000 00000000 00000000 00001001//|=    00000000 00000000 00000000 00001101//我们现在看还不是很明显  我们再做一个n |= n >>> 2;// n    00000000 00000000 00000000 00001101//n>>>2 00000000 00000000 00000000 00001111//n     00000000 00000000 00000000 00001111//发现了什么吗?我们可以观察到 其实每次做 都是在复制当前前几位1 //当这个操作都做完之后 我们可以得到我们会变成什么样子//也就是 当前的最前一位的1 后面都变为了1 如此操作我们便可以做到完成//找到2的最小次幂 那么为什么要使用位运算呢?这个问题我们就不讨论了 //计算时cup做位运算效率很高 并且哈希表是本身就是为了快n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

一个参数的构造方法  

//public HashMap(int)public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}

这个构造方法是传入一个参数 传入的参数为初始化哈希表的长度  我们也可以发现 在指定长度后 是调用了我们的带有两个参数的构造方法 其中的 initialCapacity 是我们指定的初始化的长度 DEFAULT_LOAD_FACTOR 是默认的负载因子 其中 在源码中 默认的负载因子的大小为0.75f(对的 float类型!)

不带参数的构造方法

public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}

 这是我们不带参数的构造方法 其中 会默认指定loadFactor(负载系数)为0.75以及其他字段 都为默认值 其中 值得注意到的是 HashMap的默认初始化数组的大小不是10  也不是 20 而是

16 那么为什么会是16呢?


哈希表初始化的长度

这是我们刚刚没有提及到的 我们在手动设定哈希表长度的时候 真的会是以我们手动设置的长度来构造哈希表的长度的吗?

        HashMap表的默认初始化长度为16 并且每次拓展 或者手动指定初始化长度的时候 长度         必须是2次幂 

默认初始化长度为何会是16呢?并且为何又要是2次幂呢?

        之所以我们选择16来作为默认的初始化长度 是为了服务Key映射到index的Hash算法

        从Key映射到HashMap数组对应的位置  我们都需要借助到一个Hash函数 

        这个Hash函数就是用来计算能够尽量避免哈希碰撞的长度的

        并且初始化为16 更加符合Hash算法分布均匀的要求

那么我们如何可以实现一个分布比较均匀的Hash函数呢?

        此时 我们就需要利用到另一个函数 HashCode 这个HashCode是利用Key的

        HashCode来确定在哈希表中映射的位置

 那么 是不是把Key的HashCode值和HashMap的长度进行取余运算?

        漏漏漏 大漏特漏 虽然说取余的方式很简单快捷 但是效率是比较低的 显然 我们哈希表出

        现之初就是为了提高效率的 这个操作反而有点背道而行了,所以 HashMap采用了位运

        算的方式

 面试题

        通过new HashMap(10)创建对象 此时HashMap底层的数组长度是多少?

        16   不管你传进去什么数字,返回的一定是大于等于该数字的最小2的幂次,

那么为什么是2次幂? 我们需要对于这个进行长篇大论了 等我们讲完put之后会讲解的


HashMap源码中的成员

我们去源码中寻找HashMap的特殊的 数组 我们发现 在整个HashMap中只有一个数组 就是table

但是我们同时也发现了 在我们的构造方法以及创建的时候 并没有去初始化数组的大小 

 面试题 

        为何没有在初始化或者构造方法中对数组进行初始化

        等到我们看到put中会发现 是在put方法中进行的初始化 那么为何要在put中才进行初始化呢 其实这是一个叫做懒加载的机制 是从技术底层帮我们避免了一些资源浪费 假设我们有以下的代码 如果对于map不进行使用 假设我们没有加入懒加载这个机制 就会造成资源的浪费 其中相同的技术也在List中也使用到了 (懒加载在Spring中也会经常的使用到 一定要了解到这个概念)


Put

put是HashMap中的插入方法 将指定值与此映射中的指定键关联 如果映射之前包含键的映射 则替换旧值(如果存在相同的值 会被覆盖)

    public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}

我们可以看到 put是有返回值的 这个返回值为V类型  然后我们进入putVal中查看

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; 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)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))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}

代码相当的长 我们将代码分割几个部分来进行分析

 这个判断的意思就是为了查看 如果数组为null 或者数组中有效元素个数为0 那么我们进入resize方法

final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;else {               // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];table = newTab;if (oldTab != null) {for (int j = 0; j < oldCap; ++j) {Node<K,V> e;if ((e = oldTab[j]) != null) {oldTab[j] = null;if (e.next == null)newTab[e.hash & (newCap - 1)] = e;else if (e instanceof TreeNode)((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // preserve orderNode<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);if (loTail != null) {loTail.next = null;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;}

又是超级长的代码 不过没瓜系 我们还是分开来解读

 首先 进入方法 oldTab = table = null(因为我们的table当前为空)

所以 oldCap = 0 然后我们进入判断 判断中  oldCap为0 我们将newCap与newThr都赋值为默认值

之后我们对于table进行了初始化 

可以啦

 

 以上这个代码 都不用看 因为我们现在在进行初始化 为何不需要看这些代码呢 因为这些代码都是在考虑扩容的代码 我们此时不会涉及到扩容 所以这些代码暂时不用理会 (ps:看了一天的源码 我总结出一个道理 看源码不能一行一行去读 而要去寻找重点 如果一行一行代码去读 )

好的我们又回到了put方法中 我们看当前红框中的代码 这是一个如果当前位置为空 我们便将key以及value插入 但是我们的注意力 要放到hash方法中 

 也就是当初put传入的这个hash值 这个值是如何计算出来的呢?


 面试题

        HashMap中的Key能不能为null?如果为null 则下标为多少?

        我们以上的源码可以解释这个问题 是可以为null的 且只能有一个为nill的Key 下标为0

        如果Key == null 那么直接返回hash = 0


我们还是将注意力 放到这里

假设不为空的话 它的下标是如何计算的?

 首先要通过我们的HashCode来计算一个哈希值 然后我们还要异或h>>>16位


面试题

        HashMap中秋hash值的时候用到了扰动函数 为什么要这么做呢?

        先说结论 为了减少Hash冲突发生的可能性

        我们来具体举例一下

        return (h = gril.hashCode() ^ (h >>> 16)
//假设girl的hash值是
//00101101 00101101 10100111 00101101
那么我们假设HashMap的长度为16 也就是下标为0-15
计算这个的hashMap值也很简单 我们计算下标
//00101101 00101101 10100111 00101101
//00000000 00000000 00000000 00001111
其实也就是取出最后四位嘛 直接后四位进行计算就好啦
//00000000 00000000 00000000 00000010
我们再假设 woman的hash值是这样的
//00111111 11101101 11100111 10111101
计算下标的话
//00000000 00000000 00000000 00001111
//00000000 00000000 00000000 00000010
我们可以发现  最后计算出的下标是相同的 这就是为何要加入扰动函数 扰动函数是干啥的呢?也就是说 全球60亿人 有很多人的眼睛可能是一样的 但是如果加上这些人的其他特征 那么就变得不一样了 因为世界人相同的人只有一个


下面我们便到了 插入重复元素

 这个代码也是比较复杂的 直接一句话 如果当前下标没有元素 直接插入 如果有元素 我们进行尾插(在JDK1.7之前 是头插)

那么我们如何插入 是怎么放的  此处我们不得不提到一个哈希冲突


面试题

        Hash冲突发生之后怎么解决?

        线性探测法:for循环找一下旁边有没有空位 

        链式地址法:实际上就是在同一个节点下面加 

链地址法怎么理解 假设你在坐火车 你拿着的票的位置已经坐了一个小姐姐 你该怎么办  总不能直接坐到人家小姐姐身上把(滑稽)此时我们可以加入一个上下铺的方式往后依次走


我们来看一下这个 这个红框中的是 计算负载因子 如果超过负载因子 进行扩容 并且 当一定的要求满足的时候 会转变为链表加红黑树


面试题

        HashMap链表转红黑树的条件

        链表的深度必须大于等于8

        数组的长度必须大于等于64


final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;else {               // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];table = newTab;if (oldTab != null) {for (int j = 0; j < oldCap; ++j) {Node<K,V> e;if ((e = oldTab[j]) != null) {oldTab[j] = null;if (e.next == null)newTab[e.hash & (newCap - 1)] = e;else if (e instanceof TreeNode)((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // preserve orderNode<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);if (loTail != null) {loTail.next = null;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;}

扩容的细节还是在于 扩容会进行扩容为2的次幂  


面试题

        HashMap为什么线程不安全?

        JDK1.7之前 

        ·put的时候会造成数据丢失

        ·扩容的时候 头插法会造成死循环

        JDK1.8

        ·put的时候会造成数据丢失

        ·扩容的时候 头插改成了尾插 不会出现循环

(这也可能是一部分为何要在JDK1.8之后将HashMap改为尾插法的原因之一)

Get

使用Get方法根据Key来查找Value的时候,发生了什么呢? 

首先会把输入的Key做一次Hash映射,得到对应的index 之后会去当前index下标去寻找节点是否存在 如果存在即返回V即可 get的原理是比较简单的 没有put如此的繁琐

用了10+小时来分析源码 已经吐了~知识点很多 融入文章才能看懂 有不足之处也希望多多指出 😢

相关文章:

《数据解构》HashMap源码解读

&#x1f451;作者主页&#xff1a;Java冰激凌 &#x1f4d6;专栏链接&#xff1a;数据结构 目录 了解HashMap HashMap的构造 两个参数的构造方法 一个参数的构造方法 不带参数的构造方法 哈希表初始化的长度 HashMap源码中的成员 Pt Get 了解HashMap 首先我们要明…...

Databend 开源周报 第 83 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.com 。Whats New探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。Support for WebHDFSHDFS 是大数…...

Spring | 基础

1. IOC和DI IOC&#xff1a;控制反转&#xff0c;其思想是反转资源获取的方向&#xff0c;传统的资源查找方式要求组件向容器发起请求查找资源&#xff0c;作为回应&#xff0c;容器适时的返回资源。而应用了 IOC 之后&#xff0c;则是**容器主动地将资源推送给它所管理的组件…...

windows7安装sql server 2000安装步骤 及安装过程中遇到的问题和解决方式

提示&#xff1a;文章写完后windows7安装sql server 2000安装步骤 及安装过程中遇到的问题和解决方式&#xff0c; 文章目录一、ms sql server 2000是什么&#xff1f;版本简介&#xff1a;**特点&#xff1a;****优点&#xff1a;**二、步骤1.下载安装包及Sq4补丁包2.安装 ms …...

Python 开发-批量 FofaSRC 提取POC 验证

数据来源 学习内容和目的&#xff1a; ---Request 爬虫技术&#xff0c;lxml 数据提取&#xff0c;异常护理&#xff0c;Fofa 等使用说明---掌握利用公开或 0day 漏洞进行批量化的收集及验证脚本开发Python 开发-某漏洞 POC 验证批量脚本---glassfish存在任意文件读取在默认4…...

Linux系统中部署软件

目录 1.Mysql 2.Redis 3.ZooKeeper 声明 致谢 1.Mysql 参考&#xff1a;CentOS7安装MySQL 补充&#xff1a; ① 执行&#xff1a;rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 再执行&#xff1a;yum -y install mysql-community-server ② mysql…...

PHP常用框架介绍与比较

HP是一种广泛应用于Web开发的编程语言。随着互联网的快速发展,PHP的应用场景变得越来越广泛,从简单的网站到复杂的Web应用程序都可以使用PHP来开发。为了更好地组织和管理PHP代码,开发人员经常会使用框架来提高开发效率和代码质量。 本文将介绍一些常用的PHP框架,并进行简…...

Umi + React + Ant Design Pro 项目实践(一)—— 项目搭建

学习一下 Umi、 Ant Design 和 Ant Design Pro 从 0 开始创建一个简单应用。 首先&#xff0c;新建项目目录&#xff1a; 在项目目录 D:\react\demo 中&#xff0c;安装 Umi 脚手架&#xff1a; yarn create umi # npm create umi安装成功&#xff1a; 接下来&#xff0c;…...

MySQL知识点总结(1)

目录 1、sql、DB、DBMS分别是什么&#xff0c;他们之间的关系&#xff1f; 2、什么是表&#xff1f; 3、SQL语句怎么分类呢&#xff1f; 4、导入数据 5、什么是sql脚本呢&#xff1f; 6、删除数据库 7、查看表结构 8、表中的数据 10、查看创建表的语句 11、简单的查询…...

day45第九章动态规划(二刷)

今日任务 70.爬楼梯(进阶)322.零钱兑换279.完全平方数 70.爬楼梯(进阶) 题目链接&#xff1a; https://leetcode.cn/problems/climbing-stairs/description/ 题目描述&#xff1a; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不…...

第十四届蓝桥杯第三期模拟赛原题与详解

​​​​​​​ 文章目录 一、填空题 1、1 找最小全字母十六进制数 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 给列命名 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 日期相等 1、3、1 题目描述 1、3、2 题解关键思路与解答 1、4 乘积方案数 1、4、1 题目描…...

client打包升级

目录 前言 一、client如何打包升级&#xff1f; 二、使用步骤 1.先进行改版本 2.执行打包升级命令 总结 前言 本文章主要记录一下&#xff0c;日常开发中&#xff0c;常需要进行打包升级的步骤。 一、client如何打包升级&#xff1f; # 升级发布版本 ## 修改版本 * 父p…...

Blazor_WASM之3:项目结构

Blazor_WASM之3&#xff1a;项目结构 Blazor WebAssembly项目模板可选两种&#xff0c;Blazor WebAssemblyAPP及Blazor WebAssemblyAPP-Empty 如果使用Blazor WebAssemblyAPP模板&#xff0c;则应用将填充以下内容&#xff1a; 一个 FetchData 组件的演示代码&#xff0c;该…...

OperWrt 包管理系统02

文章目录 OperWrt 包管理系统OPKG简介OPKG的工作原理OPKG命令介绍软件包的更新、安装、卸载和升级等功能软件包的信息查询OPKG配置文件说明OPKG包结构(.ipk)OPKG演示案例OperWrt 包管理系统 OPKG简介 OPKG(Open/OpenWrt Package)是一个轻量快速的软件包管理系统,是 IPKG…...

人人都学会APP开发 提高就业竞争力 简单实用APP应用 安卓浏览器APP 企业内部通用APP制作 制造业通用APP

安卓从2009年开始流程于手机、平板&#xff0c;已经是不争的非常强大生产力工具&#xff0c;更为社会创造非常高的价值&#xff0c;现在已经是202X年&#xff0c;已经十几年的发展&#xff0c;安卓平台已经无所不在。因此建议人人都学学APP制作&#xff0c;简易入门&#xff0c…...

【自然语言处理】从词袋模型到Transformer家族的变迁之路

从词袋模型到Transformer家族的变迁之路模型名称年份描述Bag of Words1954即 BOW 模型&#xff0c;计算文档中每个单词出现的次数&#xff0c;并将它们用作特征。TF-IDF1972对 BOW 进行修正&#xff0c;使得稀有词得分高&#xff0c;常见词得分低。Word2Vec2013每个词都映射到一…...

LIME: Low-light Image Enhancement viaIllumination Map Estimation

Abstract当人们在低光条件下拍摄图像时&#xff0c;图像通常会受到低能见度的影响。除了降低图像的视觉美感外&#xff0c;这种不良的质量还可能显著降低许多主要为高质量输入而设计的计算机视觉和多媒体算法的性能。在本文中&#xff0c;我们提出了一种简单而有效的微光图像增…...

源码指标编写1000问4

4.问: 哪位老师把他改成分析家的,组合公式&#xff1a;猎庄敢死队别样红(凤翔) {猎庄敢死队} rsv:(c-llv(l,9))/(hhv(h,9)-llv(l,9))100; stickline(1,50,50,1,0),pointdot,Linethick2,colorff00; k:sma(rsv,3,1); d:sma(k,3,1); rsv1:(hhv(h,9.8)-c)/(hhv(h,9.8)-llv(l,9.8))1…...

Golang中GC和三色屏障机制【Golang面试必考】

文章目录Go v1.3 标记—清楚(mark and sweep)方法Go V1.5 三色标记法三色标记过程无STW的问题强弱三色不变式插入写屏障Go V1.8的三色标记法混合写屏障机制混合写屏障场景场景1:对象被一个堆对象删除引用&#xff0c;成为栈对象的下游场景2:对象被一个栈对象删除引用&#xff0…...

MOS FET继电器(无机械触点继电器)设计输入侧电源时的电流值概念

设计输入侧电源时的问题 机械式继电器、MOS FET继电器分别具有不同的特长。基于对MOS FET继电器所具小型及长寿命、静音动作等优势的需求&#xff0c;目前已经出现了所用机械式继电器向MOS FET继电器转化的趋势。 但是&#xff0c;由于机械式继电器与MOS FET继电器在产品结构…...

LabVIEW与TCP远程实验监测

后疫情时代线上教学的普及&#xff0c;让理工类实验课的远程开展成为行业研究重点。传统线上教学工具仅适用于理论知识传播&#xff0c;针对需要动手实操的实验课程&#xff0c;存在实践操作不便、课堂监管弱化、成果验收困难等问题。国内现有远程实验系统多以虚拟仿真为主&…...

SYSTEM表空间自动增长却报ORA-01658?Oracle19C表空间管理的那些坑

Oracle 19C SYSTEM表空间自动增长失效的深度解析与实战指南 引言 在Oracle数据库管理中&#xff0c;SYSTEM表空间扮演着核心角色&#xff0c;它存储着数据字典、系统存储过程等关键元数据。然而&#xff0c;许多DBA在实际工作中都遇到过这样的困惑&#xff1a;明明设置了AUTOEX…...

智鼎在线测评通关秘籍:2024最新51job题库实战解析与避坑指南

智鼎在线测评通关秘籍&#xff1a;2024最新51job题库实战解析与避坑指南 在竞争激烈的求职市场中&#xff0c;智鼎在线测评已成为众多知名企业筛选人才的第一道门槛。据统计&#xff0c;2024年使用智鼎测评系统的企业数量同比增长35%&#xff0c;而通过率却不足40%。这份指南将…...

Llama-3.2V-11B-cot多轮对话效果展示:复杂技术问题拆解与解答

Llama-3.2V-11B-cot多轮对话效果展示&#xff1a;复杂技术问题拆解与解答 最近在测试各种大模型时&#xff0c;我特意找了一个比较“刁钻”的场景&#xff1a;让模型来解答一个复杂的系统设计问题。这类问题通常不是一两句话能说清的&#xff0c;它需要模型有很强的逻辑推理能…...

AI头像生成器镜像免配置:支持ARM架构(Mac M2/M3)的Qwen3-32B适配版

AI头像生成器镜像免配置&#xff1a;支持ARM架构&#xff08;Mac M2/M3&#xff09;的Qwen3-32B适配版 想给自己换个酷炫的头像&#xff0c;但苦于没有设计灵感&#xff1f;或者有了想法&#xff0c;却不知道怎么把它变成AI绘图工具能听懂的“语言”&#xff1f;别急&#xff…...

别再死记硬背了!用一次完整的网页访问,帮你彻底搞懂HCIA/HCIP里的TCP/IP和OSI模型

从输入网址到页面加载&#xff1a;用真实场景拆解TCP/IP与OSI模型 想象一下这个场景&#xff1a;你在浏览器地址栏输入"www.baidu.com"&#xff0c;按下回车键&#xff0c;不到一秒就看到了熟悉的搜索页面。这看似简单的操作背后&#xff0c;隐藏着一场精密的网络协议…...

AI写专著必备:优质工具大盘点,全方位提升专著撰写效率

撰写学术专著时&#xff0c;研究者需要在“内容的深度”和“覆盖的广度”之间找到一个恰当的平衡&#xff0c;而这正是许多人面临的主要难题。从深度出发&#xff0c;专著的核心论点需要具备足够的学术分量&#xff0c;不仅要清楚解答“是什么”&#xff0c;还应该深入探讨“为…...

BAAI/bge-m3应用案例:在文档检索系统中实现精准语义匹配

BAAI/bge-m3应用案例&#xff1a;在文档检索系统中实现精准语义匹配 1. 项目背景与核心价值 在当今信息爆炸的时代&#xff0c;企业和个人都面临着海量文档管理的挑战。传统的关键词搜索方式已经无法满足精准检索的需求&#xff0c;特别是在处理专业术语、同义词和跨语言文档…...

索尼Bravia家庭影院新品登场,能否重塑市场格局?

索尼Bravia新品&#xff1a;模块化家庭影院新选择索尼宣布推出七款新的Bravia家庭影院产品&#xff0c;涵盖一台电视、两款条形音箱、三款低音炮和后置音箱。除Theater Bar 5外&#xff0c;产品可自由搭配组合。其中&#xff0c;Bravia Theater Bar 7作为中高端条形音箱&#x…...

Cogito-3B量化部署实测:GTX1650/RTX3050/RTX4060不同显卡配置对比

Cogito-3B量化部署实测&#xff1a;GTX1650/RTX3050/RTX4060不同显卡配置对比 1. 测试背景与目标 Cogito-v1-preview-llama-3B作为一款性能出色的3B参数混合推理模型&#xff0c;在实际部署中面临显存占用的挑战。本次测试旨在评估该模型在不同消费级显卡上的量化部署表现&am…...