今天中午正在帶着耳機遨遊在代碼的世界裏,被運營在羣裏@
了,氣沖沖的反問我最近有刪生產的用戶數據的嗎?我確定客氣的回答道沒有呀?生產的數據我怎麼能隨隨便即可以刪除,這但是公司的紅線,再說了我也沒有數據庫的刪除權限啊,不過查詢權限仍是有的。趕忙登上堡壘機,而後去生產數據庫查一下數據,查了一下數據是還在的,嚇死了,數據還在問題就不大了,無非就是應用程序出問題了,趕忙打開代碼查看下,爲何會少了一條用戶數據,看了下代碼貌似沒啥問題就是比較簡單的一個邏輯,直接從DB
經過分頁查詢數據給到前端,而後前端負責展現,沒有啥複雜的邏輯。心想確定是前端的問題,確定是他少展現了數據,立馬把問題也甩給了他,讓他幫忙配合一塊兒看看是不是前端的問題,而後本身也仔細看看代碼,不到一分鐘前端說他展現的數據沒有問題,都是後端給到的,沒有漏掉展現的。那就是後端的bug
了羅。肉眼望去以爲可能出問題的就是分頁致使的數據丟了。不過這個分頁插件是全公司都在用,應該不至於出問題把,找不到問題只能讓測試幫忙在測試環境試試,看看是否能夠復現。前端
仔細看了一眼,竟然有個去重的方法,去重邏輯也比較簡單就是把list
經過轉爲set去下重,看下來應該就是這個去重方法有問題了
大體寫了單元測試模仿了下生產的數據,大體邏輯以下:java
public static void main(String[] args) { Set<UserDTO> userSet = new HashSet<>(); UserDTO userDTO = new UserDTO(); userDTO.setId(1); userDTO.setUserName("java金融"); UserDTO userDTO1 = new UserDTO(); userDTO1.setId(2); userDTO1.setUserName("java金融"); userSet.add(userDTO); userSet.add(userDTO1); System.out.println(userSet.size()); System.out.println(userDTO1.equals(userDTO)); } @Data static class UserDTO extends BaseDTO { private String userName; } @Data static class BaseDTO { private Integer id; }
咱們能夠輸出結果set
集合的長度是1,user1
和user2
是相等的,明明兩個user
的ID
是不同的,爲什麼會相等,咱們知道set能夠去重
是由於Set的操做,都是經過操做map來實現的,set
的add
其實就是調用map
的put
方法,map
的put
方法我相信你們應該都去看過其源碼,這裏就不詳細再說了,大概流程就是經過key經過hash算法定位到數組的下標,先判斷key
的hash
是否相等,若是相等再去判斷key的value相等,若是都相等就會覆蓋原來的值。咱們上面這個例子就是對象的hash
和value
都相等致使,可是咱們的兩個對象user1
和user2
應該是不等的,由於ID不等,那爲何會相等列?咱們仔細看下上面的代碼,咱們使用了lombok
裏面@Data
註解,咱們能夠看看這個註解幫咱們生成了哪些方法
經過上面的對比咱們能夠看出@Data
註解幫咱們生成了 注在類上,提供類的get、set、equals、hashCode、canEqual、toString
方法,這個註解確實比較方便。上面那個bug
就是由於它生成的equals方法有問題,咱們能夠把上述代碼編譯下,而後把class
裏面生成的equals
方法拷貝出來看看
面試
經過上述生成的代碼咱們能夠看出equals
方法只比較了userName
這個字段,也就是當前類的字段,並無去比較父類的字段,這就是致使兩個對象相等的緣由,咱們既然找到問題了,那解決問題就比較簡單。算法
equals
和hashCode
方法,這種方法確定是不推薦的,咱們既然用了lombok
就是爲了解放咱們的雙手,是代碼變得更加簡潔。@EqualsAndHashCode(callSuper = true) callSuper = true
會包含父類的equals
和 hashCode
方法@EqualsAndHashCode(callSuper = true)
和沒有加上這個註解生成的equals
方法的代碼差別。@EqualsAndHashCode(callSuper = true)
會去調用父類的equals
方法比較,因此這個註解也可以解決這個問題。lombok.config
的配置文件放在咱們項目的根目錄下面,內容寫上lombok.equalsAndHashCode.callSuper = call
效果等同於@EqualsAndHashCode(callSuper = true)
,這樣的話咱們就不須要爲每一個類都去加上這個註釋了,至關於在這個項目下面只要用到了@Data
註解的類都會爲其加上@EqualsAndHashCode(callSuper = true)
經過配置文件的方式就能夠全局生效。咱們再來回顧下上面的問題,歸根結底仍是因爲對象的equals
方法使用不當引發的,因此咱們在若是在判斷自定義對象業務判斷相等的時候須要去重寫下hashCode
和equals
方法,重寫的時候咱們能夠經過idea
來生成,生成後最好仍是去看一眼,看看生成的是否符合咱們的業務要求。數據庫
咱們在工做中操做一些常見的容器類好比Set、Map等來實現一些咱們本身的業務,咱們仍是有必要去看看它們的源碼的,就好比咱們經過Set來進行去重,若是咱們是使用的自定義對象的話,若是沒有重寫hashCode
和equals
方法的話,去重就會去不成功,咱們只有瞭解了它,才能真正的去用好它。在關於hashCode
和equals
阿里巴巴開發手冊也有明確的說到
後端
lombok
用起來仍是挺爽的,可是仍是有一些細節須要稍微注意下。使用前能夠大概的去看看它的官網提供的內容,否則出現莫名其妙的問題你都不知道如何下手。這個就有點相似於咱們使用SpringBoot
同樣,用起來很是爽,可是若是遇到莫名其妙的bug
解決起來就比較頭疼。數組
最後咱們再來回顧幾道關於hashCode
和equals
的比較常見的面試題?其實若是咱們只要真正看過HashMap的源碼的話,這下面幾個面試題仍是很是簡單的。
什麼狀況下須要咱們去重寫 方法?
若是隻重寫equals
方法不重寫HashCode
能夠嗎?
equals ,== 和hashcode()
的區別?ide
。單元測試