一兆解、Java中的數(shù)據(jù)類型,可分為兩類:
1.基本數(shù)據(jù)類型跑揉,也稱原始數(shù)據(jù)類型:
byte锅睛、short、char历谍、int现拒、long、float望侈、double印蔬、boolean它們之間的比較,應(yīng)該用雙等號(==)比較的是它們的值甜无。2.引用數(shù)據(jù)類型:
JAVA當(dāng)中所有的類都是繼承于Object這個基類的扛点,在Object中的基類中定義了一個equals的方法哥遮,這個方法的初始行為是比較變量(棧)內(nèi)存中存放的對象的(堆)內(nèi)存地址,用來判斷兩個對象的地址是否相同陵究,即是否是指相同一個對象眠饮。比較的是真正意義上的指針操作。
但在一些類庫當(dāng)中這個方法被覆蓋掉了铜邮,如String仪召、Integer、Date松蒜。在這些類當(dāng)中equals有其自身的實現(xiàn)扔茅,而不再是比較類在堆內(nèi)存中的存放地址了。
對于引用數(shù)據(jù)類型之間進(jìn)行equals比較秸苗,在沒有重寫equals方法的情況下召娜,它們之間的比較還是基于它們在內(nèi)存中的存放位置的地址值的,因為Object的equals方法也是用雙等號進(jìn)行比較的惊楼,所以比較后的結(jié)果跟雙等號的結(jié)果相同玖瘸。
注意:
- 比較的是操作符兩端的操作數(shù)是否是同一個對象。
- 兩邊的操作數(shù)必須是同一類型的(可以是父子類之間)才能編譯通過檀咙。
- 比較的是地址雅倒。如果是具體的阿拉伯?dāng)?shù)字的比較,值相等則為true弧可,如:
int a=10 與 long b=10L 與 double c=10.0都是相同的(為true)蔑匣,因為他們都指向地址為10的堆。 - String s=“abc"是一種非常特殊的形式棕诵,和new 有本質(zhì)的區(qū)別裁良。它是java中唯一不需要new就可以產(chǎn)生對象的途徑。以 String s=“abc”; 形式賦值在java中叫直接量年鸳,它是在常量池中而不是象new一樣放在壓縮堆中趴久。這種形式的字符串,在JVM內(nèi)部發(fā)生字符串拘留搔确,即當(dāng)聲明這樣的一個字符串后彼棍,JVM會在常量池中先查找有有沒有一個值為"abc"的對象。如果有膳算,就會把它賦給當(dāng)前引用座硕。即原來那個引用和現(xiàn)在這個引用指向了同一對象。如果沒有涕蜂,則在常量池中新創(chuàng)建一個"abc”华匾,下一次如果有 String s1 = “abc”; 又會將s1指向"abc"這個對象,即以這種形式聲明的字符串机隙,只要值相等蜘拉,任何多個引用都指向同一對象萨西。
而 String s = new String(“abcd”); 和其它任何對象一樣,每調(diào)用一次就產(chǎn)生一個對象旭旭,只要它們調(diào)用谎脯。
也可以這么理解: String str = “hello”; 先在內(nèi)存中找是不是有"hello"這個對象,如果有持寄,就讓str指向那個"hello"源梭。如果內(nèi)存里沒有"hello",就創(chuàng)建一個新的對象保存"hello"稍味。String str=new String (“hello”) 就是不管內(nèi)存里是不是已經(jīng)有"hello"這個對象废麻,都新建一個對象保存"hello"。
具體可以看下面的代碼:
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 為一個引用
String b = new String("ab"); // b為另一個引用,對象的內(nèi)容一樣
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 從常量池中查找
if (aa == bb){
System.out.println("aa==bb");// true
}
if (a == b){
System.out.println("a==b");// false模庐,非同一對象
}
if (a.equals(b)){
System.out.println("aEQb");// true
}
if (42 == 42.0) {
System.out.println("true");15 // true
}
}
}
二烛愧、equals和==的區(qū)別
equals方法最初是在所有類的基類Object中進(jìn)行定義的,源碼:
public boolean equals(Object obj) {
return (this == obj);
}
由equals的源碼可以看出這里定義的equals與雙等號是等效的(Object類中的equals與雙等號沒什么區(qū)別)掂碱。不同的原因就在于有些類(像String屑彻、Integer等類)對equals進(jìn)行了重寫,但是沒有對equals進(jìn)行重寫的類(比如我們自己寫的類)就只能從Object類中繼承equals方法顶吮,其equals方法與==就也是等效的,除非在此類中重寫equals粪薛。
對equals重新需要注意五點:
1??自反性:對任意引用值X悴了,x.equals(x)的返回值一定為true。
2??對稱性:對于任何引用值x违寿、y湃交,當(dāng)且僅當(dāng)y.equals(x)返回值為true時,x.equals(y)的返回值一定為true藤巢。
3??傳遞性:如果x.equals(y)=true搞莺,y.equals(z)=true,則x.equals(z)=true掂咒。
4??一致性:如果參與比較的對象沒任何改變才沧,則對象比較的結(jié)果也不應(yīng)該有任何改變。
5??非空性:任何非空的引用值X绍刮,x.equals(null)的返回值一定為false 温圆。
String類對equals的重寫如下:
public boolean equals(Object var1) {
if (this == var1) {
return true;
} else {
if (var1 instanceof String) {
String var2 = (String) var1;
int var3 = this.value.length;
if (var3 == var2.value.length) {
char[] var4 = this.value;
char[] var5 = var2.value;
for (int var6 = 0; var3-- != 0; ++var6) {
if (var4[var6] != var5[var6]) {
return false;
}
}
return true;
}
}
return false;
}
}
另外,雙等號比"equals"運(yùn)行速度快孩革,因為雙等號"=="只是比較引用岁歉。
三、經(jīng)典案例
如果Integer a = 3;Integer b = 3;那么【a==b】的結(jié)果是什么膝蜈?
-----true
如果Integer a = 273;Integer b = 273;那么【a==b】的結(jié)果是什么锅移?
-----false
原因:對于Integer var = ?
在-128至127范圍內(nèi)的賦值熔掺,Integer對象是在 IntegerCache.cache產(chǎn)生,會復(fù)用已有對象非剃,這個區(qū)間內(nèi)的Integer值可以直接使用==進(jìn)行判斷置逻,但是這個區(qū)間之外的所有數(shù)據(jù),都會在堆上產(chǎn)生努潘,并不會復(fù)用已有對象诽偷,推薦使用equals方法進(jìn)行判斷。