Java面试向:脑图啥是哈希

2018-09-25  本文已影响10人  拾识物者

来同学,你给我讲一下什么是嘻哈,哦不对,哈希。

一般碰到这种随便聊一聊风格的面试官,考验你运气的时刻到了,你要是回答不到正确答案上面,呵呵。

这个时候,你只好系统地全面地解答,最后还要举例说明,啥是哈希。

先放脑图:百度脑图

脑图截图

首先,与Java语言无关的,数据结构层面上的哈希表是什么?

哈希表是通过定义一个哈希函数和一个冲突解决方法,将关键字(key)映射到一个有限区间的地址上的一种数据结构。并将关键字关联的值(value)存储在这个地址上,就构成了一个使用key来查找value的哈希表。

然后,在Java中如何使用HashMap,如何定义自己的哈希

Java中的HashMap使用泛型来定义,有两个类型参数,一个是键,一个是值。public class HashMap<K,V> HashMap只是一个容器,提供了哈希函数调用的框架以及冲突解决方法,并没有定义哈希函数本身。因此需要定义哈希函数才能有效使用HashMap。

在Java语言中,除基本类型外,所有类都继承自Object,Object类提供了很多通用方法,其中就包括哈希函数 public int hashCode()。也就是说,在Java中每个对象都会有一个哈希函数,如果没有重写,那么就使用Object类提供的默认实现。很明显,这个哈希函数的输入是这个对象自身。但哈希函数的输出是一个任意整数,并不是一个有限区间,那么HashMap是怎么做到将其映射到有限区间的呢?

在HashMap内部会维护一个表,也就是一个数组(有限连续地址区间),HashMap并不需要由外部定义这个数组的大小,而是使用内部的规则自动扩展。这样外部并不知道这个数组的大小,因此也无法根据这个大小,也不应该根据这个大小来计算哈希值。所以外部提供的 hashCode() 方法返回的任意整数就有了意义,可以适应任意大小的表大小(当然不能超过int取值范围),只需要计算一下 hashCode() % N 其中 N 是表大小,就可以得到数组的索引。

有趣的是,HashMap规定这个数组的大小始终都是2的幂,这个设置使模除运算变成了位运算,也就是当X是2的幂时, (X % N) == (X & (N - 1))

Object类提供的 hashCode() 方法默认是返回对象的内存地址转换成的整数,显然这个哈希函数不怎么样。所以一个类如果有做关键字的需求,就要重写这个方法。以下是重写这个方法的原则:

上述性质中多次提到了 equals() 方法,也是 Object 类提供的通用方法之一:boolean equals(Object obj),如果想要 hasCode() 正常工作,那么同时 equals() 方法也要满足以上提到的性质。

最常用做关键字的类型非 String 莫属,它的 hashCode()equals() 方法是重写的,源代码如下:

public int hashCode() {
    int h = hash; // 这个hash变量是一个缓存字段,为了不重复计算。
    final int len = length();
    if (h == 0 && len > 0) {
        for (int i = 0; i < len; i++) {
            h = 31 * h + charAt(i);
        }
        hash = h; // 计算后存入缓存。
    }
    return h;
}
public boolean equals(Object anObject) {
    if (this == anObject) { // 快速判断自己和自己比较
        return true;
    }
    if (anObject instanceof String) { // 不是String类型直接判断为不等
        String anotherString = (String)anObject;
        int n = length();
        if (n == anotherString.length()) { // 再判断长度
            int i = 0;
            while (n-- != 0) {
                if (charAt(i) != anotherString.charAt(i)) // 判断每个字符
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

可以看出 hashCode() 的计算跟每一个字符都有关系,而且跟字符的位置也有关系,并且只与所有字符有关;而 equals() 的计算同样也是只判断字符,判断所有字符,且与位置相关。因此 String 类满足上面所述的前两个性质。至于第三个性质好不好,取决于神秘数字31,具体原因可以参考这篇文章:传送门=>走你

拜拜,煮面时顺溜

参考文章:
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
https://blog.csdn.net/bingyu880101/article/details/49866131
https://blog.csdn.net/reggergdsg/article/details/53819293
https://segmentfault.com/a/1190000010799123
https://blog.csdn.net/zhengchao1991/article/details/78916471
https://blog.csdn.net/u012104435/article/details/47951357
https://www.cnblogs.com/chinajava/p/5808416.html

上一篇 下一篇

猜你喜欢

热点阅读