HashCode 和 equals 方法
參考:
https://blog.csdn.net/SEU_Calvin/article/details/52094115
https://blog.csdn.net/jing_bufferfly/article/details/50868266
https://blog.csdn.net/anmoyyh/article/details/76019777
https://blog.csdn.net/zzg1229059735/article/details/51498310
1. 是什么标锄?
HashCode是用于查找使用的雇卷,而equals是用于比較兩個(gè)對(duì)象是否相等的交播。
HashCode:按某種規(guī)則生成的 int 類型的數(shù)值柜与,(用于確定對(duì)象存儲(chǔ)地址)咏删。
equals :比較兩個(gè)對(duì)象內(nèi)容是否相等,用于保證元素不重復(fù)拣凹。
2. 為什么需要重寫
- 重寫 hashCode:
相等的對(duì)象具有相等的hashCode這一原則森爽。而hashCode 默認(rèn)實(shí)現(xiàn)是根據(jù)對(duì)對(duì)象內(nèi)存地址換算出的值。
減少了 equals 比較的次數(shù)嚣镜,提高了效率爬迟。
若 HashCode 相同再去調(diào)用 equals,如果不同菊匿,那沒就不必在進(jìn)行 equals 的比較了. - 重寫 equals:
默認(rèn)比較的地址值付呕,但是我們一般需要比較內(nèi)容是否相等计福。
二者關(guān)系:
- 如果兩個(gè)對(duì)象 equals,那么它們的 hashCode 值一定相同
- 如果兩個(gè)對(duì)象的 hashCode 相同徽职,它們并不一定 equals
存過程:
- 先調(diào)用元素的 hashCode 方法棒搜,定位它存放的位置
- 如果這個(gè)位置無元素,就放入該位置
- 如果這個(gè)位置已經(jīng)有元素了活箕,則調(diào)用它的 equals 方法與新元素進(jìn)行比較:
- 如果相同的話就不存了。
- 如果不同(Hash key相同沖突)可款,那么在這個(gè) Hash key 的位置產(chǎn)生一個(gè)鏈表育韩,將所有產(chǎn)生相同 HashCode 的對(duì)象放到這個(gè)單鏈表上去,串在一起闺鲸。
這樣一來實(shí)際調(diào)用equals方法的次數(shù)就大大降低了筋讨,幾乎只需要一兩次。
取過程:
- hashcode不重復(fù):
通過 hashCode 直接找到存放的位置了 - hashcode重復(fù):
先通過 hashCode 來判斷兩個(gè)類是否存放某個(gè)桶里摸恍,但這個(gè)桶里可能有很多類悉罕,那么我們就需要再通過 equals 來在這個(gè)桶里找到我們要的類。
問題:重寫了equals()立镶,為什么還要重寫hashCode()呢壁袄?
違反了 hashCode 通用約定(相等的兩個(gè)對(duì)象必須具有相等的散列碼),導(dǎo)致該類無法結(jié)合所有基于散列的集合一起正常工作(HashMap媚媒、HashSet嗜逻、HashTable)。
你要在一個(gè)桶里找東西缭召,你必須先要找到這個(gè)桶栈顷,不通過重寫hashcode()來找到桶,光重寫equals()有什么用啊 嵌巷。
3. 如何重寫萄凤?重寫的原則
重寫 equals 原則:
使用 == 操作符判斷參數(shù)是否是這個(gè)對(duì)象的引用。
使用 instance of 操作符判斷”參數(shù)是否是正確的類型“搪哪。
把參數(shù)轉(zhuǎn)換成正確的類型靡努。
-
對(duì)于參數(shù)中的各個(gè)字段,判斷其是否和對(duì)象中的字段相匹配;
@Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof User)) { return false; } User user = (User) o; return user.name.equals(name) && user.age == age && user.passport.equals(passport); }
重寫 hashCode原則:
-
為不相等的對(duì)象產(chǎn)生不相等的 hashCode。
@Override public int hashCode() { int result = 17; result = 31 * result + name.hashCode(); result = 31 * result + age; result = 31 * result + passport.hashCode(); return result; }
HashSet (HashMap)怎么判斷集合元素重復(fù)噩死?
HashSet不能添加重復(fù)的元素颤难,當(dāng)調(diào)用add(Object)方法時(shí)候:
- 先比較 hashCode 是否相同,hashCode 不同則表示對(duì)象不同已维,直接添加
- hashCode 相同則繼續(xù)比較 equals 方法:
- 返回 true: 說明元素重復(fù)行嗤,就不添加
- 返回 false:說明元素不重復(fù),就添加
數(shù)組和鏈表的區(qū)別垛耳?
數(shù)組:長(zhǎng)度固定栅屏,元素在內(nèi)存中連續(xù)存儲(chǔ)飘千。
- 優(yōu)點(diǎn):查找效率比較高;
- 缺點(diǎn):長(zhǎng)度固定不靈活栈雳,插入护奈、刪除數(shù)據(jù)效率低。
鏈表:長(zhǎng)度可變哥纫,是動(dòng)態(tài)申請(qǐng)內(nèi)存空間 霉旗,元素通過指針關(guān)聯(lián)
- 優(yōu)點(diǎn):動(dòng)態(tài)申請(qǐng)或者刪除內(nèi)存空間,對(duì)于數(shù)據(jù)增加和刪除比數(shù)組靈活
- 缺點(diǎn):查詢慢
加密算法相關(guān)
MD5:
MD5 -- message-digest algorithm 5 (信息-摘要算法)蛀骇,特點(diǎn)是不管文件多大厌秒,經(jīng)過MD5后都能生成唯一的MD5值;項(xiàng)目中用于對(duì)密碼進(jìn)行加密保存擅憔,容易被反查鸵闪,所以一般會(huì)加鹽值。
BASE64:
對(duì)數(shù)據(jù)內(nèi)容進(jìn)行編碼來適合傳輸暑诸,是一種編碼算法蚌讼。常見于郵件、http加密
HMAC:
HMAC(Hash Message Authentication Code个榕,散列消息鑒別碼篡石,基于密鑰的Hash算法的認(rèn)證協(xié)議。實(shí)現(xiàn)原理:用公開函數(shù)和密鑰產(chǎn)生一個(gè)固定長(zhǎng)度的值作為認(rèn)證標(biāo)識(shí)西采,用這個(gè)標(biāo)識(shí)鑒別消息的完整性夏志。使用一個(gè)密鑰生成一個(gè)固定大小的小數(shù)據(jù)塊,即MAC苛让,并將其加入到消息中沟蔑,然后傳輸。接收方利用與發(fā)送方共享的密鑰進(jìn)行鑒別認(rèn)證等狱杰。
非對(duì)稱加密 RSA:
公鑰加密瘦材、私鑰解密;
優(yōu)點(diǎn):非對(duì)稱算法仿畸,加密程度高食棕。
缺點(diǎn):進(jìn)行的都是大數(shù)計(jì)算,速度慢
應(yīng)用場(chǎng)景:對(duì)安全性要求較高的數(shù)據(jù)加密和數(shù)字簽名错沽,如 支付寶簿晓、銀行
對(duì)稱加密
對(duì)稱加密算法,又稱秘鑰加密:用一個(gè)秘鑰來管理信息的加密解密。
優(yōu)點(diǎn):算法公開千埃、計(jì)算量小憔儿、加密速度快、加密效率高。
缺點(diǎn):秘鑰泄露就會(huì)被破解售躁。
應(yīng)用場(chǎng)景:
- 將敏感信息保存到本地的時(shí)候加密,取出的時(shí)候還原半等。
- 或上傳一些敏感數(shù)據(jù)到服務(wù)器時(shí)候蜈缤,服務(wù)端使用同樣的算法就可以解密拾氓。
常用算法:
DES :安全度在現(xiàn)代已經(jīng)不夠高
3DES:算法強(qiáng)度提高了很多,但是其執(zhí)行效率低下
AES:算法加密強(qiáng)度大底哥,執(zhí)行效率高咙鞍,使用簡(jiǎn)單,實(shí)際開發(fā)中建議選擇AES 算法趾徽。
多線程相關(guān)
1. 進(jìn)程和線程的區(qū)別
- 進(jìn)程是 CPU 資源分配的最小單位奶陈,線程是 CPU 執(zhí)行的最小單位。
- 進(jìn)程之間不能共享資源附较,而線程共享所在進(jìn)程的地址空間和其它資源。
- 一個(gè)進(jìn)程內(nèi)可擁有多個(gè)線程潦俺,進(jìn)程可開啟進(jìn)程拒课,也可開啟線程。
- 一個(gè)線程只能屬于一個(gè)進(jìn)程事示,線程可直接使用同進(jìn)程的資源,線程依賴于進(jìn)程而存在早像。
2. run() 和 start() 方法區(qū)別
- run() :僅僅是封裝被線程執(zhí)行的代碼,直接調(diào)用時(shí)普通方法
- start()::首先啟動(dòng)了線程肖爵,然后由 JVM 去調(diào)用該線程的 run() 方法卢鹦,調(diào)用兩次拋出異常
3. 線程調(diào)度模型
- 分時(shí)調(diào)度模型:
所有線程輪流使用 CPU 的使用權(quán),平均分配每個(gè)線程占用 CPU 的時(shí)間劝堪。 - 搶占式調(diào)度模型:
優(yōu)先讓優(yōu)先級(jí)高的線程使用 CPU 冀自,如果線程的優(yōu)先級(jí)相同,那么會(huì)隨機(jī)選擇一個(gè)秒啦,優(yōu)先級(jí)高的線程獲取的 CPU 時(shí)間片相對(duì)多一些熬粗。
Java 使用的是搶占式調(diào)度模型
4. 三個(gè)線程保證順序執(zhí)行
Thread.join() 方法 :join() 方法放到 start() 后面
-
newSingleThreadExecutor
ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(t1); executor.submit(t2); executor.submit(t3); executor.shutdown();
同步鎖+生產(chǎn)者消費(fèi)者模型
信號(hào)量
5. Java 開啟線程的方式
- 繼承 Thread 類
- 實(shí)現(xiàn) Runable 接口
- 避免 Java 單繼承帶來的局限性。
- 把線程同程序的代碼余境、數(shù)據(jù)分離驻呐,較好的體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想,適合多個(gè)相同的程序代碼去處理同一資源的情況芳来。
- Callable:結(jié)合線程池
6. 死鎖問題及其代碼
死鎖:指兩個(gè)或兩個(gè)以上的線程在執(zhí)行過程中含末,因爭(zhēng)奪資源產(chǎn)生的一種互相等待現(xiàn)象。