• 问题引入

    初学java的时候,Map集合给人留下的印象就是键值对{key=value}的存储方式。并且我们知道键值对的key唯一。但是Map容器真的不能存储key值相同的数据吗?查询API才发现有这么一个实现类可以存储重复的key:IdentityHashMap。

  • IdentityHashMap简介

    IdentityHashMap类同样实现了Map接口,拥有Map集合的一切特性。key值同样需要判断是不是重复,只不过就是判断的方法和其他Map的实现类不一样。

    我们来看看官方的定义:
    java.util.IdentityHashMap类利用哈希表实现 Map 接口,比较键(和值)时使用引用相等性代替对象相等性。 换句话说,在 IdentityHashMap 中,当且仅当 (k1==k2) 时,才认为两个键 k1 和 k2 相等(在正常 Map 实现(如 HashMap)中,当且仅当满足下列条件时才认为两个键 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。

    也就是说,IdentityHashMap比较的单单key的值,它不管可以的内存地址还是基本数据类型。而正常的Map实现比较的是具体的内容。

  • 简单的小Demo

public class IdentityHashMapDemo {

    public static void main(String[] args) {
        //测试key可以重复的map集合
        HashMap<Object, String> map = new HashMap<>();
        IdentityHashMap<Object, String> idenMap = new IdentityHashMap<>();
        idenMap.put("测试", "成功");
        idenMap.put("测试", "失败");

        map.put("测试", "成功");
        map.put("测试", "失败");

        System.out.println("IdentityHashMap运行结果:"+idenMap);
        System.out.println("HashMap运行结果:"+map);

        System.out.println("-------------------------------------------------------");

        idenMap.put(new String("对象"), "成功");
        idenMap.put(new String("对象"), "失败");

        map.put(new String("对象"), "成功");
        map.put(new String("对象"), "失败");

        System.out.println("IdentityHashMap运行结果:"+idenMap);
        System.out.println("HashMap运行结果:"+map);
    }
}

//运行结果
/*
    IdentityHashMap运行结果:{测试=失败}
    HashMap运行结果:{测试=失败}
    ------------------------------------------------------
    注意:这里手动过滤掉第一次存入的结果,方便观察。
    IdentityHashMap运行结果:{对象=成功, 对象=失败}

    HashMap运行结果:{对象=失败}
*/
  • 结果分析

可以看出:
如果存放的是非对象,IdentityHashMap和其他Map的实现没有区别。区别在与可一直存放的对象。使用两次new String() 创建的对象的内存地址必然不会相同,但是指向的内容是相同的。所以HashMap会认为是同一个key从而覆盖前一个key对应的值。但是IdentityHashMap只会去比较key实际的值,也就是内存地址而不会管他具体的内容。所以认为不是同一个key。

  • Q&A
String str = new String("abc"//这句代码到底创建了几个对象?
String str = "abc" //该代码和上述代码有什么区别?

/*
    第一段代码实际创建了两个对象。第二段代码创建了一个对象。("abc")就相当于第二段代码。
    这时已经创建了一次对象。再遇到new关键字时,创建第二个对象这个对象保存的是"abc"的内存地址,
    并没有真正的指向字符串"abc"。

    String str = "abc"是字符串比较特别的创建对象的方式。创建之后会作为常量保存在方法区的常量池中。
    它创建对象的时候,会先在常量池中查询有没有已经的存在的字符串常量,如果有就会把其对应的地址给它,如果没有才会创建。

*/
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐