面试记录之 HashMap 的 get 方法

文章讨论了一道关于HashMap的面试问题,涉及String和Integer对象作为键时的hash值计算。尽管a和b是两个不同的对象实例,但因为它们的值相等,所以它们的hashCode也相等,导致在HashMap中被视为相同的键。这表明HashMap判断key是否重复是基于hash值的比较。

主要是记录一次面试中问到的hashMap面试题,防止以后遇到还是不会

问题:

HashMap<String, String> map = new HashMap<>();
String a = new String(“1”);
String b = new String(“1”);
map.put(a,“value”);
那么 map.get(a) 和 map.get(b)是否相等

这个我一开始想是不相等,因为都知道map在用对象当 key 的时候,都是把对象的地址值当 key 。那 a 和 b 都是 new 出来的,地址值显然不相等。我想着应该是不相等,但是运行完,发现居然相等

在这里插入图片描述
瞬间不理解了,因此翻看了源码。先从 map 的 put 方法入手,看在是基础数据类型时候是不是有什么变化

查找原因 :从HashMap 的 get 源码入手

public V get(Object key) {
   Node<K,V> e;
   return (e = getNode(hash(key), key)) == 
   					null ? null : e.value;
}

这里发现在 get 的时候,对 key 做了 hash。所以推论,应该是两个 String 对象的 hash 值相同。那么有去看了 String 的 hash 源码,大家可以去搜索相关的 String 的hashCode算法

最终得到结论,String 的 hashCode 是根据 String 的值去算的。 因此只要是同一个值,那么 hashCode 都一样

所以这里想起来了有一个面试常说的点:

一个字符串的哈希码只算一次,就被缓存下来,以后就不用重复劳动啦!

Integer 更是简单 ,hashCode 就是值

    public int hashCode() {
        return Integer.hashCode(value);
    }
    
	public static int hashCode(int value) {
        return value;
    }

到此为止 - 结论

HashMap还是因为 key 的 hash 值相等,导致拿到想同的数据。
String 、 Integer 都是因为值相等, hashCode 也相等的原因,所以 hashMap 认为是相同的 key!

判断 HashMap 的 key 是否重复,就看 key 的 hash 值是否重复!

### HashMap 的实现原理及面试题解析 #### 一、HashMap 的基本概念 `HashMap` 是基于哈希表的键值对存储结构,在 Java 中实现了 `Map` 接口。它允许存储 `null` 键和多个 `null` 值[^1]。 #### 二、底层数据结构 在 Java 1.8 及之后版本中,`HashMap` 使用了一种混合的数据结构来提高性能: - **数组**:作为主要容器,用于存储节点(Node)。 - **链表**:当发生哈希冲突时,使用链表解决冲突。 - **红黑树**:当某个桶中的链表长度超过阈值(默认为 8),该链表会被转化为一棵平衡的红黑树以优化查找效率[^1]。 这种设计使得 `HashMap` 能够在大多数情况下保持 O(1) 时间复杂度的操作(插入、删除、查询),即使在极端情况下的时间复杂度也能通过红黑树降级到 O(log n)[^1]。 #### 三、核心方法分析 以下是几个重要的操作及其内部机制: ##### 1. 插入元素 (`put(K key, V value)` 方法) - 计算键的哈希码并映射到对应的桶索引位置。 - 如果目标位置为空,则直接创建一个新的节点存入。 - 如果目标位置已有节点,则判断是否存在相同键的情况: - 若存在相同的键,则更新其对应值。 - 否则按顺序追加至链表末尾或插入到红黑树中[^1]。 ```java public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } ``` ##### 2. 查询元素 (`get(Object key)` 方法) - 根据给定键计算出相应的哈希值找到所在槽位。 - 对于单个节点或者短小精悍型列表形式下可以直接定位;而对于较长链条以及转换成树状结构后需进一步深入比较直至匹配成功为止。 ```java public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } ``` ##### 3. 删除元素 (`remove(Object key)` 方法) - 定位指定项所在的分组区域并通过逐层递归的方式移除特定条目同时调整关联关系确保整体连贯性不受破坏。 ```java final Entry<K,V> removeEntryForKey(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode()); for (Entry<K,V>[] tab = table; ; ) { ... } } ``` #### 四、扩容机制 为了维持高效的访问速度,`HashMap` 设定了初始容量与负载因子两个参数控制何时触发扩展动作。一旦实际装载量达到预设界限就会启动重新分配过程——即新建更大规模的新表格并将旧有记录迁移过去完成升级换代工作流程。 #### 五、线程安全性问题 需要注意的是标准版 `HashMap` 并未提供同步保护措施因此不适合应用于多线程环境当中。如果确实面临此类需求可以考虑采用其他替代方案比如 `ConcurrentHashMap` 或者借助外部锁机制加以防护处理[^1]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值