定义
把任意数据转换成指定大小范围(通常很小,例如 256 字节以内)的数据。
作用
相当于从数据中提出摘要信息,因此最主要用途是数字指纹。
举例
1 | public int rengHash(String source){ |
如上代码就是一种Hash算法,只不过是一种很差的Hash算法。例如:
1 | rengHash("hehe") == 4 |
如果用做指纹,则4既是“haha”的指纹又是“hehe”的指纹。Hash有身份识别的要求,所以Hash需要有极小的碰撞率。这就需要研究Hash算法,拿到的数据可能非常大或者非常小,都需要快速得出结果并且互相之间不会碰撞,即彼此之间不会重复。
经典算法
- MD5(在防破解上已经被遗弃,太容易破解)
- SHA1
- SHA256
实际用途
数据完整性验证
从⽹络上下载文件后,通过⽐对文件的 Hash 值(例如 MD5、 SHA1),可以确认下载的文件是否有损坏。如果下载的⽂件 Hash 值和⽂件提供方给出的 Hash 值⼀致,则证明下载的文件是完好无损的。Hash就像是从一堆数据中抽取特征值,计算多次都是同一个结果,所以可以作为指纹。
快速查找:hashCode() 和 HashMap
- 为什么重写 equals() 时同时需要重写 hashCode()?
如果只重写了 equals() 而没有重写 hashCode(),则 hashCode() 的返回值就是默认的 Object 的返回值,这就有可能出现使用 equals() 来比较两个对象是不相等的而两者的 hashCode() 返回值却相等。使用 HashMap 之类的程序会出 Bug :在存入 HashMap 时,由于 hashCode 相等,对应的内存地址是一样的,这样导致了两个不一样的数据,新存入的数据却把旧数据替换掉了。
比较相等,却需要两个方法:equals() 和 hashCode(),hashCode() 是为了效率。使用 hashCode() 性能更好(使用摘要作比较)。只有重写了 hashCode(),和 Hash 相关的 java 特性比如 HashMap 才可以正常使用。当然,如果不使用 HashMap 相关的 Map 等,以上问题不存在,hashCode() 可以不用重写,但是不使用 HashMap 在开发中是难以保证的。
- 怎么重写 hashCode 方法?
把 equals() 方法中的每个用于判断相等的变量都放进 hashCode() 中,⼀起生成⼀个尽量不会碰撞的整数即可。
隐私保护
当重要数据必须暴露的时候,有事可以选择暴露它的 Hash 值(例如 MD5),以保障原数据的安全。例如网站登录时,可以只保存用户密码的 Hash 值,在每次登录验证时只需要将输⼊的密码的 Hash 值和数据库中保存的 Hash 值作比对就好,网站无需知道⽤户的密码。这样,当⽹站数据失窃时,用户不会因为自己的密码被盗导致其它网站的安全也受到威胁。
几个疑问
- Hash 是编码吗?
不是。Hash 是单向过程,往往是不可逆的,无法进行逆向恢复操作,因此 Hash 不属于编码。
- Hash 是加密吗?
不是。Hash 是单向过程,无法进行逆向恢复操作,因此 Hash 不属于加密。(记住, MD5 不是加密,加密是可逆转的,MD5 是不可逆转换!从一个大数据转换成一个小数据,不可能原样变回去,它不是压缩,只是抽取了几个特征值,以便于比较身份是否一致,但身份的所有信息是无法还原的。)
非对称加密使用Hash签名
在加密与解密一节,《签名与验证》的简单模型中,有一个缺点,签名数据和原数据是一样大的,因为签名数据能还原回原数据。假设原数据是一个10G的视频,其签名数据要10G的大小,显然是不合适的。事实上签名的做法是:先对数据进行 Hash ,再对 hash 值进行签名。模型如下:
参考资料:
腾讯课堂 HenCoder