偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

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

 [[389669]]

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

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

但就在今天,因?yàn)槎诉@篇文章中的知識(shí)竟然在大佬面前秀了一把,幫大佬解決了疑問(wèn),還換來(lái)了一個(gè)趕明兒請(qǐng)吃飯的“口頭支票”,哈哈~~

下面就來(lái)聊聊大佬遇到的奇怪問(wèn)題以及排查解決過(guò)程。

大佬的疑惑

大佬在項(xiàng)目中寫(xiě)了類(lèi)似這樣的一段代碼:

  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()方法并沒(méi)有起效,并沒(méi)有達(dá)到去重的預(yù)期。

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

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.

通過(guò)API文檔來(lái)看并沒(méi)有問(wèn)題,進(jìn)而大佬開(kāi)啟了debug模式,發(fā)現(xiàn)奇怪的是實(shí)體類(lèi)的equals方法都沒(méi)進(jìn)。

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

解決思路

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

DeviceModel實(shí)體類(lèi),簡(jiǎn)單重寫(xiě)了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實(shí)體類(lèi),重寫(xiě)了equals方法,

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

然后,構(gòu)建了測(cè)試類(lèi):

  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屬性一樣,重寫(xiě)了equals方法,理論上它們應(yīng)該是相等的,device3對(duì)象用來(lái)做對(duì)照。

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

  1. [1, 1, 2] 

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

此時(shí),大佬又發(fā)來(lái)另外一個(gè)線(xiàn)索,說(shuō)通過(guò)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); 

這種實(shí)現(xiàn)形式恰好又可以用來(lái)做對(duì)照。

問(wèn)題排查

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

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

那么,是不是因?yàn)橹貙?xiě)了equals方法,而沒(méi)有重寫(xiě)hashcode方法導(dǎo)致的呢?于是,在DeviceModel類(lèi)中新增了hashcode方法:

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

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

后續(xù)

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

因?yàn)長(zhǎng)ist的底層結(jié)構(gòu)是數(shù)組,不像Map那樣為了提升效率先對(duì)Key進(jìn)行hash處理比較。簡(jiǎn)單看一下ArrayList中contains方法的核心實(shí)現(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; 

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

小結(jié)

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

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

 

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

2021-07-28 05:01:29

Lombok前端測(cè)試

2023-03-10 08:27:07

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

2021-04-30 08:21:22

Linux管道設(shè)計(jì)

2021-10-07 16:45:06

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

2021-01-30 09:50:54

MySQL密碼服務(wù)器

2021-01-05 22:49:37

Python編程語(yǔ)言Java

2020-02-03 09:10:23

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

2024-01-04 14:16:05

騰訊紅黑樹(shù)Socket

2022-10-25 17:53:09

Java線(xiàn)程池

2019-07-29 14:38:35

服務(wù)器開(kāi)發(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

電腦磁盤(pán)微軟

2018-01-18 22:26:30

2024-05-13 07:58:52

開(kāi)源項(xiàng)目PR

2021-05-11 16:20:02

網(wǎng)站HTTPHTTPS

2016-10-17 19:14:28

2021-06-21 07:44:07

程序員面試職場(chǎng)

2022-09-27 18:19:32

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

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