成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

大佬也Hashcode方法上翻船了,不小心秀了一把!

開發(fā) 前端
大佬解決問題思路值得我們先學(xué)習(xí)一波,在大佬決定最終放棄的前,給我發(fā)消息了,問有興趣看一看沒。有這么奇怪的現(xiàn)象,怎能不研究一下呢?

 [[389669]]

本文轉(zhuǎn)載自微信公眾號「程序新視界 」,作者二師兄。轉(zhuǎn)載本文請聯(lián)系程序新視界 公眾號。   

前些天寫了幾篇面試題的文章,其中包括《重寫equals方法為什么通常會重寫hashcode方法?》,有朋友可能會說,這類面試題都是“面試造火箭,工作擰螺絲”。不可否認(rèn),有些面試題的確如此。

但就在今天,因為懂了這篇文章中的知識竟然在大佬面前秀了一把,幫大佬解決了疑問,還換來了一個趕明兒請吃飯的“口頭支票”,哈哈~~

下面就來聊聊大佬遇到的奇怪問題以及排查解決過程。

大佬的疑惑

大佬在項目中寫了類似這樣的一段代碼:

  1. List<ProjectId> list = new ArrayList<>(); 
  2. // 省略add數(shù)據(jù)操作 
  3. List<DeviceModel> models =  list.stream().map(ProjectId::getDeviceModel).distinct().collect(Collectors.toList()); 
  4. System.out.println(models); 

結(jié)果呢,這段代碼中的distinct()方法并沒有起效,并沒有達(dá)到去重的預(yù)期。

但大佬并沒有放棄,先是查了該方法的文檔:

Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.

For ordered streams, the selection of distinct elements is stable (for duplicated elements, the element appearing first in the encounter order is preserved.) For unordered streams, no stability guarantees are made.

This is a stateful intermediate operation.

通過API文檔來看并沒有問題,進(jìn)而大佬開啟了debug模式,發(fā)現(xiàn)奇怪的是實體類的equals方法都沒進(jìn)。

大佬解決問題思路值得我們先學(xué)習(xí)一波,在大佬決定最終放棄的前,給我發(fā)消息了,問有興趣看一看沒。有這么奇怪的現(xiàn)象,怎能不研究一下呢?

解決思路

根據(jù)大佬發(fā)的部分代碼和實現(xiàn)思路,把整個模擬的測試程序補充完整,創(chuàng)建了兩個實體類ProjectId和DeviceModel,并重寫了equals方法(跟大佬溝通,他重寫了equals方法,并且單獨使用是生效的)。

DeviceModel實體類,簡單重寫了equals方法,只比較字段no是否相等。

  1. @Data 
  2. public class DeviceModel { 
  3.  
  4.     private String no
  5.  
  6.     @Override 
  7.     public String toString(){ 
  8.         return no
  9.     } 
  10.  
  11.     @Override 
  12.     public boolean equals(Object other) { 
  13.  
  14.         if (this == other) { 
  15.             return true
  16.         } 
  17.         if (other == null || getClass() != other.getClass()) { 
  18.             return false
  19.         } 
  20.  
  21.         return this.toString().equals(other.toString()); 
  22.     } 

ProjectId實體類,重寫了equals方法,

  1. @Data 
  2. public class ProjectId { 
  3.  
  4.     private int id; 
  5.  
  6.     private DeviceModel deviceModel; 

然后,構(gòu)建了測試類:

  1. public class Test { 
  2.  
  3.     public static void main(String[] args) { 
  4.  
  5.         List<ProjectId> list = new ArrayList<>(); 
  6.  
  7.         DeviceModel device1 = new DeviceModel(); 
  8.         device1.setNo("1"); 
  9.         ProjectId projectId1 = new ProjectId(); 
  10.         projectId1.setDeviceModel(device1); 
  11.         projectId1.setId(1); 
  12.         list.add(projectId1); 
  13.  
  14.         DeviceModel device2 = new DeviceModel(); 
  15.         device2.setNo("1"); 
  16.         ProjectId projectId2 = new ProjectId(); 
  17.         projectId2.setDeviceModel(device2); 
  18.         projectId2.setId(1); 
  19.         list.add(projectId2); 
  20.  
  21.         DeviceModel device3 = new DeviceModel(); 
  22.         device3.setNo("2"); 
  23.         ProjectId projectId3 = new ProjectId(); 
  24.         projectId3.setDeviceModel(device3); 
  25.         projectId3.setId(2); 
  26.         list.add(projectId3); 
  27.          
  28.        List<DeviceModel> models =  list.stream().map(ProjectId::getDeviceModel).distinct().collect(Collectors.toList()); 
  29.        System.out.println(models); 
  30.  
  31.     } 

先構(gòu)建了一組數(shù)據(jù),然后讓device1與device2的no屬性一樣,重寫了equals方法,理論上它們應(yīng)該是相等的,device3對象用來做對照。

執(zhí)行上面的程序,控制臺打印如下:

  1. [1, 1, 2] 

的確還原了大佬的bug,也奇怪為什么會這樣。但既然bug已重現(xiàn),解決就是比較簡單的事了。

此時,大佬又發(fā)來另外一個線索,說通過for循環(huán)形式?jīng)]事:

  1. List<DeviceModel> results = new ArrayList<>(); 
  2. for (DeviceModel deviceModel : list.stream().map(ProjectId::getDeviceModel).collect(Collectors.toList())) { 
  3.     if (!results.contains(deviceModel)) { 
  4.         results.add(deviceModel); 
  5.     } 
  6. System.out.println(results); 

這種實現(xiàn)形式恰好又可以用來做對照。

問題排查

進(jìn)行問題排查時首先也想到了debug,但是同樣出現(xiàn)并未走equals方法的情況。

仔細(xì)看了一下代碼,發(fā)現(xiàn)在Stream處理的過程中用到了map操作。而在之前的文章中也提到,Map中判斷一個對象是否已經(jīng)存在是先通過key的hash值定位到對應(yīng)的數(shù)組下標(biāo),如果該位置上的Entry沒有值,則直接保存;如果已經(jīng)有存在的值,再通過equals方法比較值是否一樣。

那么,是不是因為重寫了equals方法,而沒有重寫hashcode方法導(dǎo)致的呢?于是,在DeviceModel類中新增了hashcode方法:

  1. @Override 
  2. public int hashCode() { 
  3.     // JDK7新增的Objects工具類 
  4.     return Objects.hash(no); 

再次執(zhí)行,測試方法,發(fā)現(xiàn)可以成功去重了。很顯然,大佬的失誤是在重寫equals方法時違背了一條原則:如果一個類的equals方法相等,那么它們的hashcode方法必須相等。由于沒有重寫hashcode方法導(dǎo)致違背這一原則。因此,在隱式使用Map時就出現(xiàn)了莫名其妙的問題。

后續(xù)

經(jīng)過這一番周折,問題終于解決。想必大家更也更加明白了為什么重寫equals方法一定要重寫hashcode方法了。后面大佬又考問我一個問題:為什么list.contains方法不會出現(xiàn)這個問題呢?

因為List的底層結(jié)構(gòu)是數(shù)組,不像Map那樣為了提升效率先對Key進(jìn)行hash處理比較。簡單看一下ArrayList中contains方法的核心實現(xiàn):

  1. public int indexOf(Object o) { 
  2.     if (o == null) { 
  3.         for (int i = 0; i < size; i++) 
  4.             if (elementData[i]==null
  5.                 return i; 
  6.     } else { 
  7.         for (int i = 0; i < size; i++) 
  8.             if (o.equals(elementData[i])) 
  9.                 return i; 
  10.     } 
  11.     return -1; 

可以看出如果對象不為null時,還是循環(huán)調(diào)用的equals方法來處理的。

小結(jié)

通過本篇文章講了一個幫大佬定位問題的故事,感謝大佬給我一個很好的寫作素材,這期間有很多值得學(xué)習(xí)和借鑒的內(nèi)容。從側(cè)面也證明,有些面試題的確有它的價值,如果你以為只是在造飛機,真有可能是在實踐中沒遇跳到坑里到而已。

最后,大佬就是因為沒好好看公眾號的上篇文章,才掉坑里的[捂臉][捂臉][捂臉]。所以,間接說明本公眾號的內(nèi)容對大家還是能提供一些幫助的,感興趣就關(guān)注一下。也歡迎直接加微信好友,探討一些有意思的技術(shù)問題。

 

責(zé)任編輯:武曉燕 來源: 程序新視界
相關(guān)推薦

2023-03-10 08:27:07

for循環(huán)項目線性結(jié)構(gòu)

2021-07-28 05:01:29

Lombok前端測試

2021-04-30 08:21:22

Linux管道設(shè)計

2021-10-07 16:45:06

MySQL數(shù)據(jù)庫

2021-01-30 09:50:54

MySQL密碼服務(wù)器

2021-01-05 22:49:37

Python編程語言Java

2020-02-03 09:10:23

數(shù)據(jù)庫刪庫刪庫跑路

2024-01-04 14:16:05

騰訊紅黑樹Socket

2022-10-25 17:53:09

Java線程池

2019-07-29 14:38:35

服務(wù)器開發(fā)工具

2021-01-08 09:36:23

程序員比特幣黑客

2020-10-26 08:56:32

技術(shù)總監(jiān)程序員

2024-04-18 08:00:23

openInula?React響應(yīng)式 API

2021-04-15 21:55:38

電腦磁盤微軟

2018-01-18 22:26:30

2021-05-11 16:20:02

網(wǎng)站HTTPHTTPS

2024-05-13 07:58:52

開源項目PR

2016-10-17 19:14:28

2021-06-21 07:44:07

程序員面試職場

2022-09-27 18:19:32

Java數(shù)據(jù)結(jié)構(gòu)
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 精品久久精品 | 中文字幕一区二区三区精彩视频 | 国产一区二区三区日韩 | 一级毛片,一级毛片 | 美女网站视频免费黄 | 91久久精品一区二区二区 | 亚洲激情一区二区三区 | 久久五月婷| 久久1区 | 亚洲一区视频在线播放 | 国产免费视频在线 | 国产精品久久久久久久久久久久 | 国产高潮好爽受不了了夜夜做 | 午夜精品久久久久久久久久久久 | 亚洲国产精品人人爽夜夜爽 | 亚洲国产aⅴ成人精品无吗 综合国产在线 | 91午夜在线| 一区二区三区欧美 | www国产亚洲精品久久网站 | www.激情.com | 成人在线播放网站 | 雨宫琴音一区二区在线 | 91免费高清 | 久久免费精品 | 亚洲大片在线观看 | 日韩一级黄色片 | 成人中文字幕在线 | 玖玖国产 | 一级a性色生活片久久毛片波多野 | 青青久视频 | 中文字幕亚洲精品 | 东京久久 | 久久精品亚洲精品国产欧美kt∨ | 9久久婷婷国产综合精品性色 | 亚洲黄色一级 | 亚洲成人黄色 | 中文字幕亚洲视频 | www.99热| 中日韩欧美一级片 | 青青草社区 | 一区精品视频在线观看 |