HashMap的底层数据结构和源码分析

HashMap 的数据结构

HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。数组是用来确定桶的位置,利用元素的key的hash值对数组长度取模得到。链表是用来解决hash冲突问题,当出现hash值一样的情形,就在数组上的对应位置形成一条链表。

从上图中可以看出,HashMap 底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个 HashMap 的时候,就会初始化一个数组。也就是说在构造函数中,其创建了一个 Entry 的数组,Entry 是一个 static class,其中包含了 key 和 value,也就是键值对,另外还包含了一个 next 的 Entry 指针。我们可以总结出:Entry 就是数组中的元素,每个 Entry 其实就是一个 key-value 对,它持有一个指向下一个元素的引用,这就构成了链表。

当我们往 HashMap 中 put 元素的时候,先根据 key 的 hashCode 重新计算 hash 值,根据 hash 值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

hash冲突

就是键(key)经过hash函数得到的结果作为地址去存放当前的键值对(key-value)(这个是hashmap的存值方式),但是却发现该地址已经有人先来了,一山不容二虎,就会产生冲突。这个冲突就是hash冲突了。

一句话说就是:如果两个不同对象的hashCode相同,这种现象称为hash冲突。

(1)两个对象相等,hashcode一定相等
(2)两个对象不等,hashcode不一定不等
(3)hashcode相等,两个对象不一定相等
(4)hashcode不等,两个对象一定不等

简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据 hash 算法来决定其在数组中的存储位置,在根据 equals 方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry 时,也会根据 hash 算法找到其在数组中的存储位置,再根据 equals 方法从该位置上的链表中取出该Entry。

### MyBatis 中判断 `int` 类型是否为空的解决方案 在 MyBatis 中处理 Java 基本数据类型如 `int` 时,由于基本类型的默认值不是 `null` 而是 `0`,这可能导致一些意外行为。为了正确处理这种情况,通常建议使用对应的包装类 `Integer` 来代替 `int`。 #### 使用 `Integer` 替代 `int` 通过将参数定义为 `Integer` 可以允许其接受 `null` 值: ```xml <select id="getUserById" parameterType="java.lang.Integer" resultType="User"> SELECT * FROM users WHERE user_id = #{userId} </select> ``` 这样可以在映射文件中的条件语句里直接测试该变量是否为 `null` 或者有具体数值[^1]。 #### 处理 SQL 查询中的零值情况 对于那些可能接收到来自前端应用传递过来的实际业务逻辑上的 “空白” 输入(即整数形式下的 &#39;0&#39;),可以通过调整 `<if>` 测试表达式的写法来区分真正的未赋值状态与合法输入之间的差异: ```xml <where> <if test="_parameter != null and _parameter.intValue() != 0"> AND column_name = #{value} </if> </where> ``` 这里 `_parameter` 是指当前上下文中正在评估的那个对象实例;而 `.intValue()` 方法则用来获取实际存储于其中的具体数值以便进一步比较[^2]。 #### 设置 JDBC Type Result Map 另外,在某些情况下还需要特别指定 JDBC type 属性以及配置适当的结果集映射(result map),从而确保数据库端的数据能够被正确解释并转换成预期的目标类型。例如针对日期字段应设置合适的 jdbcType 参数[^3]: ```xml <resultMap id="BaseResultMap" type="com.example.User"> <!-- other columns --> <result property="birthDate" column="birthdate" jdbcType="DATE"/> </resultMap> <!-- ... --> <insert id="insertSelective" parameterType="com.example.User"> INSERT INTO t_user ( birthdate, ... ) VALUES ( <trim prefix="(" suffix=")" suffixOverrides=","> <if test="birthDate != null">#{birthDate,jdbcType=DATE},</if> ... </trim> ) </insert> ``` 以上措施有助于提高应用程序面对不同类型数据源时的一致性稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值