确定Java等价性的新时代?
幾個(gè)月前,我讀了一篇題為“確定Java等價(jià)性的新時(shí)代?”的博客文章。 這在某種程度上與我當(dāng)時(shí)在我那令人腳的副項(xiàng)目Java :: Geci中開(kāi)發(fā)的內(nèi)容非常吻合 。 我建議您暫停閱讀,閱讀原始文章,然后再返回此處,即使您知道一定比例的讀者也不會(huì)回來(lái)。 這篇文章是關(guān)于如何在Java中正確實(shí)現(xiàn)equals()和hashCode() ,以及一些有關(guān)應(yīng)該如何實(shí)現(xiàn)或應(yīng)該如何實(shí)現(xiàn)的思想。 在本文中,我將為那些不閱讀原始文章的人詳細(xì)介紹這些內(nèi)容,并補(bǔ)充我的想法。 部分使用Java :: Geci的方式解決了這些問(wèn)題,并且在本文結(jié)尾處,應(yīng)如何在equals()和hashCode()處理遞歸數(shù)據(jù)結(jié)構(gòu)。 (請(qǐng)注意,就在我閱讀文章的那一天,我也在完善mapper生成器以處理遞歸數(shù)據(jù)結(jié)構(gòu)。這與我實(shí)際上正在解決的問(wèn)題非常共鳴。)
如果您回來(lái)甚至沒(méi)有讀完原始文章,甚至連Liam Miller-Cushon所引用的JDK信函中的標(biāo)題為“ 等效性 ”,在這里,您都可以從我的角度對(duì)最重要的陳述進(jìn)行簡(jiǎn)短總結(jié)/從中學(xué)習(xí)文章:
- 手動(dòng)生成equals()和hashCode()很麻煩。
- 自Java 7以來(lái),JDK就提供了支持,但是仍然存在方法的代碼,并且必須對(duì)其進(jìn)行維護(hù)。
- IDE可以為這些方法生成代碼,但是重新生成它們?nèi)圆皇亲詣?dòng)化過(guò)程,而手動(dòng)執(zhí)行重新生成是容易出錯(cuò)的維護(hù)過(guò)程。 (又名您忘記了運(yùn)行發(fā)電機(jī))
Liam Miller-Cushon的標(biāo)題為“ Equivalence ”的JDK信件列出了equals()和hashCode()實(shí)現(xiàn)中的典型錯(cuò)誤。 值得在更多細(xì)節(jié)中重申這些內(nèi)容。 (某些文字被逐字引用。)
- “覆蓋Object.equals(),但不覆蓋hashCode()。 (Object.hashCode的合同規(guī)定,如果兩個(gè)對(duì)象相等,則在兩個(gè)對(duì)象中的每個(gè)對(duì)象上調(diào)用hashCode()方法必須產(chǎn)生相同的結(jié)果。實(shí)現(xiàn)equals()而不是hashCode()使得情況不太可能。)”,這是一個(gè)菜鳥(niǎo)錯(cuò)誤,您可能會(huì)說(shuō)您永遠(yuǎn)不會(huì)犯錯(cuò)。 是的,如果您是高級(jí)程序員,但在智力方面還不是高級(jí),例如:忘記了牙齒修復(fù)的位置,那么您永遠(yuǎn)不會(huì)忘記在創(chuàng)建hashCode()時(shí)創(chuàng)建hashCode() equals() 。 但是請(qǐng)注意,這是生命中非常短暫的時(shí)間。 許多初級(jí)人員也構(gòu)成了代碼庫(kù),缺少的hashCode()可能總是潛伏在Java代碼的干草堆深處,我們必須使用所有經(jīng)濟(jì)上可行的措施來(lái)避免它們不存在。
- “等于無(wú)條件遞歸的實(shí)現(xiàn)。” 這是一個(gè)常見(jiàn)的錯(cuò)誤,甚至老年人也多次忽略了這個(gè)可能的錯(cuò)誤。 因?yàn)槲覀兪褂玫臄?shù)據(jù)結(jié)構(gòu)通常不是遞歸的,所以這幾乎不是問(wèn)題。 當(dāng)它們是遞歸的時(shí), equals()或hashCode()方法的粗心的遞歸實(shí)現(xiàn)可能會(huì)導(dǎo)致無(wú)限循環(huán),堆棧溢出和其他不便之處。 我將在文章結(jié)尾討論這個(gè)話題。
- “比較不匹配的字段或吸氣劑對(duì),例如a == that.a && b == that.a. “這是一個(gè)主題輸入錯(cuò)誤,很容易像主題->典型那樣被忽略。
- 等于在給定null參數(shù)時(shí)拋出NullPointerException的實(shí)現(xiàn)。 (它們應(yīng)該返回false。)
- 等于在給定類(lèi)型錯(cuò)誤的參數(shù)時(shí)拋出ClassCastException的實(shí)現(xiàn)。 (它們應(yīng)該返回false。)
- 通過(guò)委派給hashCode()來(lái)實(shí)現(xiàn)equals() hashCode() 。 (哈希經(jīng)常沖突,因此將導(dǎo)致誤報(bào)。)
- 考慮未在相應(yīng)的equals()方法中測(cè)試的hashCode()中的狀態(tài)。 (相等的對(duì)象必須具有相同的hashCode() 。)
- 將引用相等或hashCode()用于數(shù)組成員的equals()和hashCode()實(shí)現(xiàn)。 (他們可能打算使用值相等和hashCode() 。)
- 其他錯(cuò)誤(不在建議的范圍之內(nèi)):使用錯(cuò)誤,例如比較兩個(gè)靜態(tài)不同的類(lèi)型,或帶有定義的非本地錯(cuò)誤(例如,覆蓋等號(hào)和更改語(yǔ)義,破壞可替換性)
我們?nèi)绾伪苊膺@些錯(cuò)誤? 一種可能性是增強(qiáng)語(yǔ)言,如所提到的建議所建議的那樣,以便可以以聲明的方式描述方法hashCode()和equals() ,而實(shí)際的實(shí)現(xiàn)是常規(guī)且麻煩的,由編譯器完成。 這是光明的未來(lái),但我們必須等待。 Java因Swift整合思想而聞名。 當(dāng)實(shí)現(xiàn)某些功能時(shí),它將以向后兼容的方式永久保存。 因此,選擇是快速實(shí)施它,可能以錯(cuò)誤的方式實(shí)施并永久使用它。 或等到業(yè)界完全確定必須以哪種語(yǔ)言實(shí)現(xiàn)它,然后再到那時(shí)再實(shí)現(xiàn)它。 Java正在遵循第二種開(kāi)發(fā)方式。
正如我在《 您的代碼是多余的... 》一文中所描述的那樣,這是語(yǔ)言發(fā)展引起的語(yǔ)言短缺。 暫時(shí)性的短缺將在以后解決,但就目前而言,我們必須處理這種短缺。
解決這種短缺的方法之一就是代碼生成,這就是Java :: Geci出現(xiàn)的地方。
Java :: Geci是一個(gè)代碼生成框架,非常適合創(chuàng)建代碼生成器,以幫助減少針對(duì)特定領(lǐng)域問(wèn)題的代碼冗余。 代碼生成器在單元測(cè)試執(zhí)行期間運(yùn)行,這可能會(huì)稍晚一些,因?yàn)榇a已被編譯。 但是,此問(wèn)題已通過(guò)以下方式修復(fù):如果“測(cè)試”的代碼生成了任何代碼并執(zhí)行了編譯,則生成“測(cè)試”的代碼將失敗,并且第二次測(cè)試也將不再失敗。
旁注:這種工作方式可能對(duì)任何軟件開(kāi)發(fā)人員都非常熟悉:讓我們?cè)俅芜\(yùn)行它,可能會(huì)起作用!
從技術(shù)的角度來(lái)看,在編程語(yǔ)言發(fā)展不足的情況下,Java :: Geci也是一樣。 出于特定領(lǐng)域的原因而生成的代碼與出于語(yǔ)言演進(jìn)不足的原因而生成的代碼之間沒(méi)有技術(shù)上的區(qū)別。 但是,在語(yǔ)言演變問(wèn)題的情況下,您可能會(huì)找到其他也可以解決該問(wèn)題的代碼生成工具。 要生成equals()和hashCode() ,可以使用集成開(kāi)發(fā)環(huán)境。 沒(méi)有什么比從IDE中選擇菜單然后單擊單擊“生成等于和hashCode”更簡(jiǎn)單了。
假設(shè)生成的代碼行為良好,這可以解決以上所有問(wèn)題之一。 唯一的問(wèn)題是,無(wú)論何時(shí)更新代碼,它都不會(huì)再次運(yùn)行代碼生成器來(lái)更新生成的代碼。 IDE無(wú)法與Java :: Geci競(jìng)爭(zhēng)。 設(shè)置Java :: Geci框架的步驟比單擊幾個(gè)菜單項(xiàng)要多。 您需要測(cè)試依賴(lài)項(xiàng),必須創(chuàng)建一個(gè)單元測(cè)試方法,并且必須注釋需要生成器的類(lèi),或者,作為替代,您必須在包含生成代碼的代碼中插入一個(gè)編輯器折疊塊。 但是,在那之后,您可以忘記生成器,而無(wú)需擔(dān)心團(tuán)隊(duì)中的任何開(kāi)發(fā)人員都忘記了重新生成equals()或hashCode()方法。
帶走
- 為一個(gè)類(lèi)擁有適當(dāng)?shù)膃quals()和hashCode()方法并不像看起來(lái)那樣簡(jiǎn)單。 手動(dòng)編寫(xiě)它們幾乎不是最好的方法。
- 使用生成工具來(lái)生成它們,并確保所生成的代碼和代碼生成不會(huì)出現(xiàn)上述任何常見(jiàn)錯(cuò)誤。
- 如果只需要Q&D,則使用IDE菜單并生成方法。 另一方面,如果您有一個(gè)較大的代碼庫(kù),并且有許多開(kāi)發(fā)人員在其中工作,并且代碼生成可能需要重新執(zhí)行,則可以使用自動(dòng)執(zhí)行代碼生成的工具。 示例:Java :: Geci。
- 使用最新版本的工具(例如Java),以免落后于可用技術(shù)。
翻譯自: https://www.javacodegeeks.com/2019/10/a-new-era-for-determining-equivalence-in-java.html
總結(jié)
以上是生活随笔為你收集整理的确定Java等价性的新时代?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java 泛型示例_使用Java泛型的模
- 下一篇: 企业远程办公解决方案来了如何解决公司电脑