为什么 HashMap 常用 String 对象作 key

偶然的一次机会看到了这个题目,有一个网上的朋友说在面试的时候面到了这道题目,没有能给出解释。这里就谈一谈自己的理解。

在《Java 编程思想》中有这么一句话:设计 hashCode() 时最重要的因素就是对同一个对象调用 hashCode() 都应该产生相同的值。String 类型的对象对这个条件有着很好的支持,因为 String 对象的 hashCode() 值是根据 String 对象的内容计算的,并不是根据对象的地址计算。

下面是 String 类源码中的 hashCode() 方法:String 对象底层是一个 final 修饰的 char 类型的数组,hashCode() 的计算是根据字符数组的每个元素进行计算的,所以内容相同的 String 对象会产生相同的散列码。

/**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
public int hashCode() {
        int h = hash;     //private int hash; // Default to 0
        if (h == 0 && value.length > 0) {
            char val[] = value;    //获得 String 对象底层的字符数组

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];    //在计算的时候加的是 int 类型的 ascii 码
            }
            hash = h;
        }
        return h;
    }

我们希望的是我们在用对象作为 key 时,我们在获取的时候也依然能够根据重新定义 key 获得对应的 value。就像下面这样,但是它却不能正常工作:这两个对象产生的散列码是不同的,所以在进行 equals() 判断的时候这两个对象被认定为是不同的对象,自然也就获取不到对应的 value。

如果你想获得 map 中存储的“123”,那么你只有把 test 对象作为 key 才能获取到,我们试图用一种简单的方法就能让它工作,但是这显然与我们的初衷相背驰。所以非 String 类型的数据类型在判断 key 相同时所需要的条件太过苛刻。

    Test test = new Test();
    Map<Test,String> map1 = new HashMap<>();
    map1.put(test,"123");

    System.out.print(map1.get(new Test()));    //我们试图取出对应的 value

    /**
    * 输出
    * null
    */

但是 String 类型的对象就不一样了,内容相同的两个 String 对象具有相同的散列码,并且经过 equals() 判断后返回值为 true,所以在进行查找的时候它可以正常工作。

    String key = "key";
    HashMap<String,Integer> map = new HashMap<>();
    map.put(key,123);

    System.out.println(map.get("key"));

    /**
    * 输出
    * 123
    */

总结:在使用 String 类型的对象做 key 时我们可以只根据传入的字符串内容就能获得对应存在 map 中的 value 值,而非 String 类型的对象在获得对应的 value 时需要的条件太过苛刻,首先要保证散列码相同,并且经过 equals() 方法判断为 true 时才可以获得对应的 value。

PS:
如果你想把自定义的对象作为 key,那也是可以的,你只需要重写 hashCode() 方法与 equals() 方法即可,按照你自己的意愿定义散列码。这篇博文属于博主自己的对这个问题理解,如果哪里有不准确或者是错误的理解还请大家指正。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值