掘金 后端 ( ) • 2024-05-15 09:51

theme: orange highlight: a11y-dark

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

在这里插入图片描述


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

环境说明: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类的部分源码:

public class IdentityHashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, java.io.Serializable, Cloneable
{
    // ...
}

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

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的简单示例:

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提供了以下构造函数:

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对应的旧值。

示例:

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。

示例:

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。

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的基本用法:

测试结果

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」教程导航帖》,本专栏致力打造最硬核 Java 零基础系列学习内容,🚀打造全网精品硬核专栏,带你直线超车;欢迎大家订阅持续学习。功不唐捐,久久为功!

「赠人玫瑰,手留余香」,咱们下期拜拜~~

附录源码

如上涉及所有源码均已上传同步在「Gitee」,提供给同学们一对一参考学习,辅助你更迅速的掌握。

☀️建议/推荐你

无论你是计算机专业的学生,还是对编程感兴趣的跨专业小白,都建议直接入手「滚雪球学Java」专栏;该专栏不仅免费,bug菌还郑重承诺,只要你学习此专栏,均能入门并理解Java SE,以全网最快速掌握Java语言,每章节源码均同步「Gitee」,你真值得拥有;学习就像滚雪球一样,越滚越大,带你指数级提升。

码字不易,如果这篇文章对你有所帮助,帮忙给bugj菌来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。

📣关于我

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 20w+;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!