今天我們將討論一個非常重要和有趣的話題,即比較對象與對象(比較字符串和等于)。那么在Java中,對象A究竟什么時候等于對象B呢?讓我們嘗試寫一個例子:控制臺輸出:假等待,停止。為什么這兩輛車不相等?我們?yōu)樗鼈兎峙淞讼嗤膶傩?,但比較的結(jié)果是假的。答案很簡單。該運(yùn)算符比較對象引用,而不是對象屬性。兩個對象甚至可能有 500 個具有相同值的字段,但比較它們?nèi)匀粫a(chǎn)生 false。
==汽車1和汽車2指向兩個不同的對象,即指向兩個不同的地址。想象一下,你正在比較人們的情況。當(dāng)然,在世界的某個地方,有一個人和你有同樣的名字,眼睛的顏色,年齡,身高,頭發(fā)顏色等。這讓你們在很多方面都很相似,但你們?nèi)匀徊皇请p胞胎——你們顯然不是同一個人。
當(dāng)我們使用它來比較兩個對象時,運(yùn)算符使用大致相同的邏輯。但是,如果您需要程序使用不同的邏輯,該怎么辦?例如,假設(shè)您的程序執(zhí)行 DNA 分析。它比較了兩個人的遺傳密碼,并確定他們是否是雙胞胎。 控制臺輸出:false 我們得到相同的邏輯結(jié)果(因為我們沒有太大變化),但現(xiàn)在這個邏輯不好!畢竟,在現(xiàn)實生活中,DNA分析應(yīng)該給我們100%的保證,我們有雙胞胎站在我們面前。但是我們的程序和操作員告訴我們相反的情況。我們?nèi)绾胃淖冞@種行為,并確保程序在DNA匹配時輸出正確的結(jié)果?Java對此有一種特殊的方法:==
==等于().喜歡到字符串()方法,我們之前討論過,等于()屬于對象class — Java 中最重要的類,所有其他類派生自的類。但等于()不會自行更改程序的行為: 控制臺輸出: false 完全相同的結(jié)果,那么我們需要此方法做什么呢?:/一切都很簡單。這里的問題是,我們目前正在使用此方法,因為它是在
對象類。如果我們進(jìn)入代碼對象類并查看方法的實現(xiàn),這就是我們將看到的:這就是程序行為沒有改變的原因!完全相同的運(yùn)算符(用于比較引用)在
==等于()方法對象類。但是這種方法的訣竅在于我們可以覆蓋它。覆蓋方式編寫自己的等于()我們的方法男人類,給它我們需要的行為!目前,我們不喜歡這樣一個事實:人1.等于(人2)本質(zhì)上等效于人1 == 人2.以下是我們在這種情況下將執(zhí)行的操作: 控制臺輸出:true 現(xiàn)在我們得到了一個完全不同的結(jié)果!通過編寫我們自己的
等于()方法并使用它而不是標(biāo)準(zhǔn)方法,我們已經(jīng)產(chǎn)生了正確的行為:現(xiàn)在,如果兩個人具有相同的DNA,程序報告“DNA分析已證明他們是雙胞胎”并返回真實!通過覆蓋等于()方法在你的類中,你可以很容易地創(chuàng)建任何你需要的對象比較邏輯。事實上,我們剛剛談到了對象比較。在我們面前,關(guān)于這個主題仍然有一個很大的獨(dú)立課程(如果你有興趣,你現(xiàn)在瀏覽一下)。
在 Java 中比較字符串
為什么我們要將字符串比較與其他所有內(nèi)容分開考慮?現(xiàn)實情況是,字符串本身就是編程中的一個主題。首先,如果你把所有曾經(jīng)編寫的Java程序都拿來,你會發(fā)現(xiàn)其中大約25%的對象是字符串。所以這個話題非常重要。其次,比較字符串的過程確實與其他對象非常不同??紤]一個簡單的例子:控制臺輸出:false 但是為什么我們得到假呢?畢竟,字符串完全相同,逐字逐句:/您可能已經(jīng)猜到了原因:
這是因為運(yùn)算符比較引用==!清楚s1和s2內(nèi)存中具有不同的地址。如果你想到這一點,那么讓我們重新制作我們的例子:現(xiàn)在我們又有兩個引用,但結(jié)果恰恰相反:控制臺輸出:真的無助地困惑?讓我們弄清楚發(fā)生了什么。操作員確實比較了內(nèi)存地址。這總是正確的,你不需要懷疑它。這意味著如果
==s1 == s2返回 true,則這兩個字符串具有相同的地址。這是真的!現(xiàn)在是時候向您介紹用于存儲字符串的特殊內(nèi)存區(qū)域:字符串池
字符串池是用于存儲您在程序中創(chuàng)建的所有字符串值的區(qū)域。為什么創(chuàng)建它?如前所述,字符串表示所有對象的巨大百分比。任何大型程序都會創(chuàng)建大量字符串。創(chuàng)建字符串池是為了節(jié)省內(nèi)存:字符串被放置在那里,然后創(chuàng)建的字符串引用相同的內(nèi)存區(qū)域 - 無需每次都分配額外的內(nèi)存。每次你寫字符串 = “.....”程序檢查字符串池中是否有相同的字符串。如果有,則不會創(chuàng)建新字符串。新的引用將指向字符串池中的相同地址(相同字符串所在的地址)。所以當(dāng)我們寫
s2指向 與 相同的位置s1.第一條語句在字符串池中創(chuàng)建新字符串。第二個語句僅引用與s1.您可以再制作500個相同的字符串,結(jié)果不會改變。等一會。如果這是真的,那么為什么這個例子以前不起作用呢? 我認(rèn)為你的直覺已經(jīng)告訴你原因=)在進(jìn)一步閱讀之前嘗試猜測。您可以看到這兩個字符串以不同的方式聲明。一個帶有新操作員,另一個沒有新操作員。原因就在這里。當(dāng)
新增功能運(yùn)算符用于創(chuàng)建對象,它強(qiáng)制為對象分配新的內(nèi)存區(qū)域。以及使用新增功能不會最終出現(xiàn)在字符串池中 — 它成為一個單獨(dú)的對象,即使它的文本與字符串池中的字符串完全匹配。也就是說,如果我們編寫以下代碼:在內(nèi)存中,它看起來像這樣:
每次使用創(chuàng)建新對象時新增功能,則分配一個新的內(nèi)存區(qū)域,即使新字符串內(nèi)的文本是相同的!看來我們已經(jīng)找到了操作員。但是我們的新認(rèn)識呢,==等于()方法? 控制臺輸出:真正有趣。我們確信
s1和s2指向內(nèi)存中的不同區(qū)域。但是等于()方法仍然告訴我們它們是相等的。為什么?請記住,我們之前說過等于()方法可以被覆蓋以比較我們想要的對象?這就是他們所做的字符串類。它覆蓋等于()方法。它不是比較引用,而是比較字符串中的字符序列。如果文本相同,則它們是如何創(chuàng)建的或存儲在何處并不重要:無論是在字符串池中還是在單獨(dú)的內(nèi)存區(qū)域中。比較的結(jié)果將為真。順便說一句,Java允許您執(zhí)行不區(qū)分大小寫的字符串比較。通常,如果其中一個字符串具有全部大寫字母,則比較的結(jié)果將為 false:控制臺輸出:false 對于不區(qū)分大小寫的比較,
字符串類具有等于虛無案例()方法。如果您只關(guān)心比較特定字符的順序而不是字母大小寫,則可以使用它。例如,這在比較兩個地址時可能會有所幫助:在這種情況下,我們顯然是在談?wù)撓嗤牡刂?,因此使?/p>
等于虛無案例()方法。
字符串.實習(xí)生() 方法
這字符串類還有一個棘手的方法:實習(xí)生();這實習(xí)生()方法直接與字符串池一起工作。如果您撥打?qū)嵙?xí)生()方法在一些字符串上:
它檢查字符串池中是否有匹配的字符串
如果有,它將返回對池中字符串的引用
如果不是,它將字符串添加到字符串池并返回對它的引用。
使用后實習(xí)生()字符串引用上的方法,該方法使用新增功能,我們可以使用運(yùn)算符將其與字符串池中的字符串引用進(jìn)行比較。 控制臺輸出:true 當(dāng)我們之前比較這些字符串時,沒有==
實習(xí)生(),結(jié)果是錯誤的?,F(xiàn)在實習(xí)生()方法檢查字符串“CodeGym是學(xué)習(xí)Java的最佳站點!”是否在字符串池中。當(dāng)然,它是:我們創(chuàng)建它與我們檢查
String s1 = "CodeGym is the best website for learning Java!";
s1和返回的引用s2.實習(xí)生()指向內(nèi)存的同一區(qū)域。當(dāng)然,他們確實:)總之,記住并應(yīng)用這個重要的規(guī)則:始終使用等于()比較字符串的方法!在比較字符串時,我們幾乎總是想比較它們的字符,而不是引用,內(nèi)存區(qū)域或其他任何東西。這等于()方法完全符合您的需要。