HashSet能同时存入引号包围和new出来的两个String对象吗

今天面试遇到一个很有意思的问题,先说一下这个问题的背景,面试的时候被问到有两个String对象,分别是String a="abc"和String b=new String(“abc”),问这两个对象同时存进HashSet吗?了解这个问题之前我们先看看HashSet的源码。

HashSet源码解析

话不多说,先看代码。

public HashSet() {
    map = new HashMap<>();
}

首先是HashSet的构造方法,我们可以看到HashSet在构造方法里调用了一下HashMap的构造方法。欸????等等!HashMap???

我们再往下继续看其他函数的源码。

public Iterator<E> iterator() {
    return map.keySet().iterator();
}

public int size() {
    return map.size();
}

public boolean isEmpty() {
    return map.isEmpty();
}

public boolean contains(Object o) {
    return map.containsKey(o);
}

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
}

public void clear() {
    map.clear();
}

注意看add方法,好家伙,原来HashSet底层就是直接定义了一个HashMap的对象,要存的东西都直接以HashMap键的形式往里面存啊!

好的,那我们接下来就来扒一扒HashMap键的原理。

HashMap源码解析

下面的代码是HashMap的put方法的源码,看过前面博客的同学们应该很了解这个过程了。

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

我们看一下这个hash方法的源码是什么样子的。首先判断这个key值是否为空,是的话就直接返回0,否则返回key值的hashcode与hashcode无符号右移16位的异或结果。

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

懂了,两个对象如果hashCode相同的话那么通过这个hash方法是可以得到相同的hash值。HashMap的部分完了吗?没有!我们先回顾一下HashMap插入数据的内容然后再分析String的hashCode是怎么得到的。

我们把目光放到putVal函数的这部分代码:

if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;

相信大家已经很熟悉了,就是HasMap的数组里的hash值和当前插入的节点的hash值进行对比,一样的话说明发生了Hash冲突。然后还需要看一下数组中的节点和待插入的节点是不是完全一样或者说值完全相等(equals返回true),是的话直接替换。懂了吗?两个String对象equals一定会返回true!所以我们接下来看一下hashCode的问题。

String源码分析

下面是String的hashCode的源码,首先是h被hash赋值了,而hash默认是0,这里的value数组其实就是String的字符数组。两个String对象值一样的话,value数组必然也是一样的。后面没啥好看的了,h是0,value数组完全相等,那么经过if语句里的一通操作,返回的h值还是一样的。


private final char value[];

private int hash; // Default to 0

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

我们可以得出结论:只要两个String对象的值相等,那么他们的hashCode一定是相等的。

总结

好了,前面一通分析大家应该已经知道上面问题的答案了。由于两个对象的值以及hasCode值都相等,因此存入HashMap的键也就是一样的,因此后面存入的String对象将会覆盖前面存入的String对象,而HashSet是利用HashMap的key进行存储的,自然就只能存入一个对象了。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值