首先器钟,這是 Java 規(guī)范津坑。為什么要有這樣的規(guī)范呢妙蔗?還得從 hash 原理說(shuō)起。
舉個(gè)例子〗澹現(xiàn)在有 1000 個(gè)字符串眉反,都是人名,比如 Jack穆役、Tom 等寸五。最簡(jiǎn)單的存儲(chǔ)方式是,將這 1000 個(gè)字符串存入一個(gè)數(shù)組里耿币。假如 Jack 存在于 311 這個(gè)位置梳杏。如果我現(xiàn)在要找到它,必須得和 數(shù)組里的的數(shù)據(jù)逐個(gè)比較淹接,從下標(biāo)為1的位置開(kāi)始比較十性,然后和下標(biāo)為2的位置比較,直到比較到 311 這個(gè)位置的數(shù)據(jù)塑悼。
那么劲适,有沒(méi)有更高效的方式呢?有厢蒜。很多霞势。hash 就是最典型的一種。說(shuō) hash 之前斑鸦,要提到數(shù)組的一個(gè)特點(diǎn)了愕贡。在一個(gè)數(shù)組里,假如我知道某個(gè)數(shù)據(jù)(比如Jack)存放的位置(下標(biāo) 311)巷屿,我就可以一步就取出這個(gè)數(shù)據(jù)(Jack)颂鸿。試想,將 Jack 和數(shù)組下標(biāo) 311 通過(guò)某種方式關(guān)聯(lián)起來(lái)攒庵。那么查找效率是不是會(huì)變得高效嘴纺?我們先嘗試著關(guān)聯(lián)一下看看。
比如浓冒,如果將 a-z 和 1-26 這些數(shù)字映射起來(lái)栽渴。那么Jack就是 J=10,a=1,c=3,k=11.那么 Jack = 101311 和 1000 取模為 311。那么我通過(guò)這種方式稳懒,將 Jack 存在下標(biāo)為 311 的單元格中闲擦。等到取數(shù)據(jù)的時(shí)候慢味,比如有個(gè)場(chǎng)景,查詢(xún)數(shù)組里有沒(méi)有 Jack 這個(gè)字符串墅冷。那么我可以用 Jack 經(jīng)過(guò)同樣的計(jì)算方式纯路,得到一個(gè)值為 311 。然后在數(shù)組里寞忿,獲取到下標(biāo)為 311 這個(gè)單元格里面的數(shù)據(jù)驰唬。這樣,查找效率就比一個(gè)一個(gè)順著往下比較高很多倍腔彰。
hash碰撞的緣故叫编,可能一個(gè)單元格里存有多個(gè)數(shù)據(jù),比如 311這個(gè)格子里不僅有Jack, 還有 Tom 霹抛,所以需要 equals 來(lái)進(jìn)行字符串匹配了搓逾。
這里,可以看出 hashCode 和 equals 方法分別做了什么杯拐。某個(gè)數(shù)據(jù)霞篡,通過(guò)算法,得到 hashCode端逼,然后將這個(gè)數(shù)據(jù)存入下標(biāo)等于 hashCode 的單元格里朗兵。這樣,就將數(shù)據(jù)和數(shù)組下標(biāo)關(guān)聯(lián)起來(lái)了裳食。因?yàn)閔ash碰撞矛市,一個(gè)單元格可能存有多個(gè)數(shù)據(jù), equals 就是為了比較一個(gè)單元格里是否有目標(biāo)數(shù)據(jù)诲祸。
所以浊吏,重寫(xiě) equals 需要重寫(xiě) hashCode。
總之救氯,hash算法是利用數(shù)組尋下標(biāo)訪問(wèn)速度高效的特點(diǎn)找田。將存儲(chǔ)的元素和數(shù)組下標(biāo)關(guān)聯(lián)起來(lái)。來(lái)達(dá)到高查找效率的目標(biāo)着憨。
Java 中墩衙,當(dāng)用到HashMap,HashSet這類(lèi)的集合框架時(shí),比如甲抖,將自己新建的類(lèi)作為 HashMap 的 key漆改。這種情況下,需要重寫(xiě)hashCode和equals方法准谚。重寫(xiě)的情景很少挫剑,但是掌握了hash原理,也就能搞明白數(shù)據(jù)庫(kù)的hash索引柱衔、一致性hash等等樊破。
hash算法的優(yōu)點(diǎn):查找效率高
hash算法的缺點(diǎn):無(wú)法進(jìn)行部分匹配查詢(xún)愉棱。比如key是jack,我想找key里包含“jac”對(duì)應(yīng)的value哲戚。沒(méi)有順序奔滑,無(wú)法在hash里面進(jìn)行排序。擴(kuò)容的時(shí)候顺少,需要重新hash,效率會(huì)比較低朋其。
備注:Object 的 hashcode 不一定是對(duì)象地址引用,要看實(shí)際 JVM祈纯。== 比較的是地址引用令宿,而 Oject 的 equals 是封裝 ==