浅谈equals与==
一、前言
示例代碼:
public static void main(String[] args) throws IOException {String str1 = new String("hello");String str2 = new String("hello");String str3 = "cde";String str4 = "cde";int i1 = 3;int i2 = 3;Integer i3 = new Integer(4);Integer i4 = new Integer(4);System.out.println(str1 == str2); //falseSystem.out.println(str1.equals(str2)); //trueSystem.out.println(str3 == str4); //trueSystem.out.println(str3.equals(str4)); //trueSystem.out.println(i1 == i2); //trueSystem.out.println(i3 == i4); //false}返回結(jié)果:
false true true true true false為什么str1與str2輸出的結(jié)果不一樣而str3與str4輸出的結(jié)果一樣,i1與i2輸出結(jié)果一樣而i3與i4輸出結(jié)果不一樣呢?==和equals方法之間的區(qū)別是什么?如果在初學(xué)Java的時(shí)候這個(gè)問(wèn)題不弄清楚,就會(huì)導(dǎo)致自己在以后編寫(xiě)代碼時(shí)出現(xiàn)一些低級(jí)的錯(cuò)誤。今天就來(lái)一起了解一下==和equals方法的區(qū)別之處。
二、區(qū)別
i1==i2結(jié)果為true,這個(gè)很容易理解,變量i1和變量i2存儲(chǔ)的值都為3,肯定是相等的。而為什么str1和str2兩次比較的結(jié)果不同?要理解這個(gè)其實(shí)只需要理解基本數(shù)據(jù)類(lèi)型變量和非基本數(shù)據(jù)類(lèi)型變量的區(qū)別。
在Java中有8種基本數(shù)據(jù)類(lèi)型:
整型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)
浮點(diǎn)型:float(4 byte), double(8 byte)
字符型: char(2 byte)
布爾型: boolean(JVM規(guī)范沒(méi)有明確規(guī)定其所占的空間大小,僅規(guī)定其只能夠取字面值”true”和”false”)
對(duì)于這8種基本數(shù)據(jù)類(lèi)型的變量,變量直接存儲(chǔ)的是“值”,因此在用關(guān)系操作符==來(lái)進(jìn)行比較時(shí),比較的就是 “值” 本身。要注意浮點(diǎn)型和整型都是有符號(hào)類(lèi)型的,而char是無(wú)符號(hào)類(lèi)型的(char類(lèi)型取值范圍為0~2^16-1)。
也就是說(shuō)比如:
int i1=3;int i2=3;變量i1和變量i2都是直接存儲(chǔ)的”3”這個(gè)數(shù)值,所以用==比較的時(shí)候結(jié)果是true。
而對(duì)于非基本數(shù)據(jù)類(lèi)型的變量,在一些書(shū)籍中稱(chēng)作為 引用類(lèi)型的變量。比如上面的str1就是引用類(lèi)型的變量,引用類(lèi)型的變量存儲(chǔ)的并不是 “值”本身,而是于其關(guān)聯(lián)的對(duì)象在內(nèi)存中的地址。比如下面這行代碼:
String str1;這句話(huà)聲明了一個(gè)引用類(lèi)型的變量,此時(shí)它并沒(méi)有和任何對(duì)象關(guān)聯(lián)。
而 通過(guò)new String(“hello”)來(lái)產(chǎn)生一個(gè)對(duì)象(也稱(chēng)作為類(lèi)String的一個(gè)實(shí)例),并將這個(gè)對(duì)象和str1進(jìn)行綁定:
str1= new String("hello");那么str1指向了一個(gè)對(duì)象(很多地方也把str1稱(chēng)作為對(duì)象的引用),此時(shí)變量str1中存儲(chǔ)的是它指向的對(duì)象在內(nèi)存中的存儲(chǔ)地址,并不是“值”本身,也就是說(shuō)并不是直接存儲(chǔ)的字符串”hello”。這里面的引用和C/C++中的指針很類(lèi)似。
因此在用==對(duì)str1和str2進(jìn)行比較時(shí),得到的結(jié)果是false。因此它們分別指向的是不同的對(duì)象,也就是說(shuō)它們實(shí)際存儲(chǔ)的內(nèi)存地址不同。
equals方法是基類(lèi)Object中的方法,因此對(duì)于所有的繼承于Object的類(lèi)都會(huì)有該方法。為了更直觀地理解equals方法的作用,直接看Object類(lèi)中equals方法的實(shí)現(xiàn)。
下面是Object類(lèi)中equals方法的實(shí)現(xiàn):
public boolean equals(Object obj) {return (this == obj); }很顯然,在Object類(lèi)中,equals方法是用來(lái)比較兩個(gè)對(duì)象的引用是否相等,即是否指向同一個(gè)對(duì)象。
但是有些朋友又會(huì)有疑問(wèn)了,為什么str1與str2的equals比較輸出結(jié)果是true?
要知道究竟,可以看一下String類(lèi)的equals方法的具體實(shí)現(xiàn)。
下面是String類(lèi)中equals方法的具體實(shí)現(xiàn):
@Override public boolean equals(Object other) {if (other == this) {return true;}if (other instanceof String) {String s = (String)other;int count = this.count;if (s.count != count) {return false;}// TODO: we want to avoid many boundchecks in the loop below// for long Strings until we have array equality intrinsic.// Bad benchmarks just push .equals without first getting a// hashCode hit (unlike real world use in a Hashtable). Filter// out these long strings here. When we get the array equality// intrinsic then remove this use of hashCode.if (hashCode() != s.hashCode()) {return false;}char[] value1 = value;int offset1 = offset;char[] value2 = s.value;int offset2 = s.offset;for (int end = offset1 + count; offset1 < end; ) {if (value1[offset1] != value2[offset2]) {return false;}offset1++;offset2++;}return true;} else {return false;}}可以看出,String類(lèi)對(duì)equals方法進(jìn)行了重寫(xiě),用來(lái)比較指向的字符串對(duì)象所存儲(chǔ)的字符串是否相等。
其他的一些類(lèi)諸如Double,Date,Integer等,都對(duì)equals方法進(jìn)行了重寫(xiě)用來(lái)比較指向的對(duì)象所存儲(chǔ)的內(nèi)容是否相等。
到此還沒(méi)有結(jié)束,在示例代碼中還有str3和str4,這兩個(gè)對(duì)象的==和equals比較結(jié)果都返回true,這與str1與str2的情況不符,為什么呢?這里涉及到String的緩沖池問(wèn)題。
分析如下:
String作為一個(gè)對(duì)象來(lái)使用
例子一:對(duì)象不同,內(nèi)容相同,”==”返回false,equals返回true
String s1 = new String("java"); String s2 = new String("java");System.out.println(s1==s2); //false System.out.println(s1.equals(s2)); //true運(yùn)行結(jié)果:
false true例子二:同一對(duì)象,”==”和equals結(jié)果相同
String s1 = new String("java"); String s2 = s1;System.out.println(s1==s2); //true System.out.println(s1.equals(s2)); //true運(yùn)行結(jié)果:
true trueString作為一個(gè)基本類(lèi)型來(lái)使用
如果值不相同,對(duì)象就不相同,所以”==” 和equals結(jié)果一樣
String s1 = "java"; String s2 = "java";System.out.println(s1==s2); //true System.out.println(s1.equals(s2)); //true運(yùn)行結(jié)果:
true true如果String緩沖池內(nèi)不存在與其指定值相同的String對(duì)象,那么此時(shí)虛擬機(jī)將為此創(chuàng)建新的String對(duì)象,并存放在String緩沖池內(nèi)。
如果String緩沖池內(nèi)存在與其指定值相同的String對(duì)象,那么此時(shí)虛擬機(jī)將不為此創(chuàng)建新的String對(duì)象,而直接返回已存在的String對(duì)象的引用。
想了解String緩沖池的,可以看看這篇文章:Java提高篇 —— String緩沖池
三、總結(jié)
對(duì)于==而言
如果作用于基本數(shù)據(jù)類(lèi)型的變量,則直接比較其存儲(chǔ)的 “值”是否相等
如果作用于引用類(lèi)型的變量,則比較的是所指向的對(duì)象的地址
對(duì)于equals而言
equals方法不能作用于基本數(shù)據(jù)類(lèi)型的變量
如果沒(méi)有對(duì)equals方法進(jìn)行重寫(xiě),則比較的是引用類(lèi)型的變量所指向的對(duì)象的地址
諸如String、Date等類(lèi)對(duì)equals方法進(jìn)行了重寫(xiě)的話(huà),比較的是所指向的對(duì)象的內(nèi)容
總結(jié)
以上是生活随笔為你收集整理的浅谈equals与==的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 二度烫伤怎么赔偿 二度烧伤赔偿标准
- 下一篇: 支付宝etc信用记账卡是信用卡吗?一文带