前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >滚雪球学Java(65-3):详解Java IdentityHashMap的内部实现原理

滚雪球学Java(65-3):详解Java IdentityHashMap的内部实现原理

原创
作者头像
bug菌
发布2024-08-04 18:42:52
500
发布2024-08-04 18:42:52
举报
文章被收录于专栏:滚雪球学Java

  咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE相关知识点了,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~


🏆本文收录于 **[「滚雪球学Java」 ](https://blog.csdn.net/weixin_43970743/category_9600553.html)专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅**!持续更新中,up!up!up!!

代码语言:java
复制
环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

前言

  Java是一种面向对象的高级编程语言,它具有平台无关性,这意味着Java编译器生成的字节码可以在任何支持Java的平台上运行。Java有许多不同的集合类,包括List、Map、Set等。其中,Map是一个键值对的映射,它允许你使用键来查找值。在Java中,有一个名为IdentityHashMap的独特的Map实现。

摘要

  IdentityHashMap是Java中的一种Map实现,它与其他Map实现不同之处在于,它使用对象的引用作为键的比较方式,而不是使用equals()方法。这意味着,即使两个对象具有相同的值,如果它们的引用不同,它们被认为是不同的键。因此,在IdentityHashMap中,可以将不同的对象作为键存储在Map中。

IdentityHashMap解读

概述

  IdentityHashMap在Java 1.4中被引入,它位于java.util包中。它继承了AbstractMap类并实现了Map接口。在IdentityHashMap中,一个键值对由一个键和一个值组成,其中键是对象的引用,值是任何对象。IdentityHashMap中的键被认为是相同的,当且仅当它们的引用完全相同。这就意味着,即使两个对象的值相同,如果它们的引用不同,它们仍然被视为不同的键。

源代码解析

  IdentityHashMap的源代码可以在Java的官方文档中找到。以下是IdentityHashMap类的部分源码:

代码语言:java
复制
public class IdentityHashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, java.io.Serializable, Cloneable
{
    // ...
}

  在IdentityHashMap中,键值对被存储在Entry对象中。以下是IdentityHashMap.Entry类的摘要:

代码语言:java
复制
static class Entry<K,V> extends HashMap.Entry<K,V> {
    Entry(K key, V value) {
        super(key, value);
    }
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            if (e.getKey() == key)
                return true;
        }
        return false;
    }
    // ...
}

  可以看出,IdentityHashMap.Entry类扩展了HashMap.Entry类。Entry类中的equals()方法比HashMap.Entry类中的equals()方法少了对值的比较,而是只比较键的引用。如果两个Entry对象具有相同的键引用,则认为它们相等。如果两个Entry对象的键引用不同,则认为它们不相等。这使得IdentityHashMap能够将不同的对象作为键存储在Map中。

  如下是部分源码截图:

拓展:

  这是一个静态嵌套类 Entry<K,V>,继承自 HashMap.Entry<K,V>。它有一个带有两个参数的构造函数 Entry(K key, V value),在构造函数中调用父类的构造函数。它还重写了 equals(Object o) 方法,用于在 HashMap 中判断两个 Entry 是否相等。

  在 equals(Object o) 方法中,首先判断传入的对象是否与自身相等,如果相等则返回 true。接着判断传入的对象是否为 Map.Entry 类型,如果是,则将它转换为 Map.Entry<?,?> 类型。最后,判断传入的对象的 key 是否与当前 Entry 的 key 相等,如果相等则返回 true,否则返回 false。

  注意,这里用的是 == 进行判断,因此比较的是 key 的引用是否相等。如果要比较 key 的值是否相等,应该使用 Objects.equals() 方法。

应用场景案例

  IdentityHashMap通常用于需要精确比较对象引用的场景。下面是一个使用IdentityHashMap的简单示例:

代码语言:java
复制
IdentityHashMap<String, Integer> hashMap = new IdentityHashMap<>();
String s1 = "hello";
String s2 = new String("hello");
hashMap.put(s1, 1);
hashMap.put(s2, 2);
System.out.println(hashMap.size()); // 输出 2

  在这个示例中,我们创建了两个具有相同值的String对象。然后,我们使用这两个String对象作为不同的键将它们添加到IdentityHashMap中。由于IdentityHashMap使用对象的引用比较键,因此它将这两个String对象视为不同的键。因此,IdentityHashMap中有两个键值对。

优缺点分析

优点:

  • 它可以将不同的对象作为键存储在Map中,这使得它非常适合需要精确比较对象引用的场景。
  • 它的实现比其他Map实现更简单,因为它不需要使用equals()方法来比较键。

缺点:

  • IdentityHashMap的性能可能低于其他Map实现。因为它使用对象的引用来比较键,而不是使用equals()方法,所以在查找和插入操作中,它需要更多的处理时间和内存。

类代码方法介绍

构造函数

IdentityHashMap提供了以下构造函数:

代码语言:java
复制
public IdentityHashMap() // 创建一个空的IdentityHashMap
public IdentityHashMap(int expectedMaxSize) // 创建具有给定初始容量的IdentityHashMap
public IdentityHashMap(Map<? extends K,? extends V> m) // 创建具有与指定Map相同映射关系的IdentityHashMap

方法

  IdentityHashMap继承了AbstractMap类,并实现了Map接口。它提供了许多与其他Map实现相同的方法,例如put()、get()、remove()、size()和clear()等方法。此处只列出IdentityHashMap中与其他Map实现不同的方法:

void putIfAbsent(Object key, Object value)

如果指定的键不与任何值关联,则将它与指定的值关联。否则,不执行任何操作。

拓展:

该代码是Java中Map接口中的putIfAbsent()方法的方法签名。

该方法的作用是:如果指定的键值对(key-value pair)在Map中不存在,则将该键值对插入到Map中,否则不执行任何操作。

方法参数说明:

  • key:要插入的键(key)。
  • value:要插入的值(value)。

方法返回值说明:

  • 如果之前不存在key对应的val,则返回null。
  • 如果之前存在key对应的val,则返回该key对应的旧值。

示例:

代码语言:java
复制
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.putIfAbsent("apple", 2);  // 不会执行任何操作,返回1
map.putIfAbsent("banana", 3); // 执行插入操作,返回null
boolean remove(Object key, Object value)

如果指定的键与指定的值相关联,则删除该键值对。否则,不执行任何操作。

拓展:

该方法是用于从映射中移除具有给定键和值的映射(键值对)。

  • 参数:key 表示映射中要移除的键;value 表示映射中要移除的值。
  • 返回值:若映射中存在该键值对,则返回 true,否则返回 false。

示例:

代码语言:java
复制
Map<String, Integer> map = new HashMap<>();
map.put("A", 10);
map.put("B", 20);
map.put("C", 30);

boolean result1 = map.remove("B", 20); // 移除键为 "B",值为 20 的映射
System.out.println(result1); // 输出 true

boolean result2 = map.remove("D", 40); // 没有键为 "D",值为 40 的映射
System.out.println(result2); // 输出 false

System.out.println(map); // 输出 {A=10, C=30}
Object replace(Object key, Object value)

如果指定的键已经与某个值相关联,则替换该键的值,并返回以前的值。否则,返回null。

拓展:

这个方法是一个Map接口中的方法,用于替换键值对中的旧值。它接收两个参数:要替换的键和新值。如果替换成功,则返回旧值,否则返回null。

以下是方法的详细解释:

参数:

  • key:要替换的键。
  • value:新值。

返回值:

替换成功,返回旧值(老的value);替换失败(该键不存在),返回null。

实现:

实现此方法的类必须实现Map接口。

作用:

用于替换Map中指定键的值。

示例:假设有一个Map对象map,包含键值对 ("a", 1), ("b", 2),现在我们要将键为 "a" 对应的值 1 替换为 10。

代码语言:java
复制
map.replace("a", 10); // 将键 "a" 的值替换为 10

替换完成后,该map对象的键值对变为:("a", 10), ("b", 2)。此时,replace方法返回值为1,因为替换前 "a" 的值为 1。

boolean replace(Object key, Object oldValue, Object newValue)

如果指定的键已经与指定的旧值相关联,则用指定的新值替换该键的值,并返回true。否则,不执行任何操作。

拓展:

方法名称:replace

参数:Object key,Object oldValue,Object newValue

返回值:boolean

功能描述:根据指定的键(key),替换对应的值(oldValue)为新值(newValue),并返回替换是否成功的布尔值(true表示替换成功,false表示替换失败)。

注意事项:如果Map中不存在指定的键值对,则不进行替换,并返回false。此方法是线程安全的,即使在多个线程同时修改Map中的值也不会出现问题。

测试用例

以下是一个简单的main函数测试用例,它演示了IdentityHashMap的基本用法:

测试结果

代码语言:java
复制
package com.demo.javase.day65_3;

import java.util.IdentityHashMap;

/**
 * IdentityHashMap示例演示
 *
 * @Author bug菌
 * @Source 公众号:猿圈奇妙屋
 * @Date 2023-11-06 16:53
 */
public class IdentityHashMapTest {

    public static void main(String[] args) {
        IdentityHashMap<String, Integer> hashMap = new IdentityHashMap<>();
        String s1 = "hello";
        String s2 = new String("hello");
        hashMap.put(s1, 1);
        hashMap.put(s2, 2);
        System.out.println(hashMap.get(s1)); // 输出 1
        System.out.println(hashMap.get(s2)); // 输出 2
        System.out.println(hashMap.size()); // 输出 2
        hashMap.remove(s1);
        System.out.println(hashMap.size()); // 输出 1
    }
}

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

  该程序演示了IdentityHashMap的使用。在该程序中,创建一个IdentityHashMap对象,其中键的类型为String,值的类型为Integer。然后,将两个键值对添加到IdentityHashMap中,这两个键具有相同的值"hello",但是一个键是使用字符串字面量创建的,另一个键是使用new操作符创建的新字符串。因为这两个键是不同的对象,所以它们在IdentityHashMap中被视为具有不同的身份。

  在输出中,第一个打印语句输出s1的值,即"hello"的值1,第二个打印语句输出s2的值,即也是"hello"的值2。第三个打印语句输出IdentityHashMap的大小,即2,因为其中有两个键值对。最后,使用remove方法从IdentityHashMap中删除s1,并再次输出其大小,这次输出1,因为只剩下包含s2的键值对。

小结

  IdentityHashMap是Java中的一种独特的Map实现。它使用对象的引用作为键的比较方式,而不是使用equals()方法。这意味着,即使两个对象具有相同的值,如果它们的引用不同,它们被认为是不同的键。IdentityHashMap通常用于需要精确比较对象引用的场景。它的实现比其他Map实现更简单,因为它不需要使用equals()方法来比较键。但是,由于它使用对象的引用比较键,而不是使用equals()方法,因此在查找和插入操作中,它需要更多的处理时间和内存。

总结

  IdentityHashMap是Java中的一种独特的Map实现,它使用对象的引用作为键的比较方式。IdentityHashMap通常用于需要精确比较对象引用的场景。它比其他Map实现更简单,因为它不需要使用equals()方法来比较键,但是它的性能可能低于其他Map实现。IdentityHashMap提供了多个与其他Map实现不同的方法,例如putIfAbsent()、remove()、replace()等方法。在使用IdentityHashMap时,需要注意使用对象的引用作为键的比较方式可能会导致一些意外的结果。

☀️建议/推荐你

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学Java」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门Java编程,就像滚雪球一样,越滚越大,指数级提升。

  码字不易,如果这篇文章对你有所帮助,帮忙给bug菌来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。   同时也推荐大家关注我的硬核公众号:「猿圈奇妙屋」 ;以第一手学习bug菌的首发干货,不仅能学习更多技术硬货,还可白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!

📣关于我

  我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,掘金等平台签约作者,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计30w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。


--End

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 摘要
    • IdentityHashMap解读
      • 概述
        • 源代码解析
          • 应用场景案例
            • 优缺点分析
              • 类代码方法介绍
                • 构造函数
                • 方法
              • 测试用例
                • 测试结果
                • 测试结果
                • 测试代码分析
              • 小结
              • 总结
              • ☀️建议/推荐你
              • 📣关于我
              相关产品与服务
              腾讯云代码分析
              腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档