1、==
java中的數(shù)據(jù)類型兵琳,可分為兩類:
1.基本數(shù)據(jù)類型狂秘,也稱原始數(shù)據(jù)類型
byte,short,char,int,long,float,double,boolean 他們之間的比較骇径,應用雙等號(==),比較的是他們的值。
2.引用類型(類者春、接口破衔、數(shù)組)
當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址钱烟,所以晰筛,除非是同一個new出來的對象,他們的比較后的結果為true拴袭,否則比較后結果為false读第。
對象是放在堆中的,棧中存放的是對象的引用(地址)拥刻。由此可見'=='是對棧中的值進行比較的怜瞒。如果要比較堆中對象的內容是否相同,那么就要重寫equals方法了般哼。
例:
public static void main(String[] args) {
int int1 = 12;
int int2 = 12;
Integer Integer1 = new Integer(12);
Integer Integer2 = new Integer(12);
Integer Integer3 = new Integer(127);
Integer a1 = 127;
Integer b1 = 127;
Integer a = 128;
Integer b = 128;
String s1 = "str";
String s2 = "str";
String str1 = new String("str");
String str2 = new String("str");
System.out.println("int1==int2:" + (int1 == int2));
System.out.println("int1==Integer1:" + (int1 == Integer1));
System.out.println("Integer1==Integer2:" + (Integer1 == Integer2));
System.out.println("Integer3==b1:" + (Integer3 == b1));
System.out.println("a1==b1:" + (a1 == b1));
System.out.println("a==b:" + (a == b));
System.out.println("s1==s2:" + (s1 == s2));
System.out.println("s1==str1:" + (s1 == str1));
System.out.println("str1==str2:" + (str1 == str2));
}
輸出結果:
int1==int2:true
int1==Integer1:true //Integer會自動拆箱為int吴汪,所以為true
Integer1==Integer2:false//不同對象,在內存存放地址不同逝她,所以為false
Integer3==b1:false//Integer3指向new的對象地址,b1指向緩存中127地址睬捶,地址不同黔宛,所以為false
a1==b1:true
a==b:false
s1==s2:true
s1==str1:false
str1==str2:false
Integer b1 = 127;java在編譯的時候,被翻譯成-> Integer b1 = Integer.valueOf(127);
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
看一下源碼大家都會明白,對于-128到127之間的數(shù)擒贸,會進行緩存臀晃,Integer b1 = 127時,會將127進行緩存介劫,下次再寫Integer i6 = 127時徽惋,就會直接從緩存中取,就不會new了座韵。所以a1==b1:true a==b:false
2险绘、equals
1、默認情況(沒有覆蓋equals方法)下equals方法都是調用Object類的equals方法誉碴,而Object的equals方法主要用于判斷對象的內存地址引用是不是同一個地址(是不是同一個對象)宦棺。下面是Object類中equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
定義的equals與==是等效的
2 、要是類中覆蓋了equals方法黔帕,那么就要根據(jù)具體的代碼來確定equals方法的作用了代咸,覆蓋后一般都是通過對象的內容是否相等來判斷對象是否相等。下面是String類對equals進行了重寫:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
即String中equals方法判斷相等的步驟是:
1.若A==B 即是同一個String對象 返回true
2.若對比對象是String類型則繼續(xù)成黄,否則返回false
3.判斷A呐芥、B長度是否一樣逻杖,不一樣的話返回false
4。逐個字符比較思瘟,若有不相等字符荸百,返回false
這里對equals重新需要注意五點:
1 自反性:對任意引用值X,x.equals(x)的返回值一定為true.
2 對稱性:對于任何引用值x,y,當且僅當y.equals(x)返回值為true時潮太,x.equals(y)的返回值一定為true;
3 傳遞性:如果x.equals(y)=true, y.equals(z)=true,則x.equals(z)=true
4 一致性:如果參與比較的對象沒任何改變管搪,則對象比較的結果也不應該有任何改變
5 非空性:任何非空的引用值X,x.equals(null)的返回值一定為false
實現(xiàn)高質量equals方法的訣竅:
1.使用==符號檢查“參數(shù)是否為這個對象的引用”铡买。如果是更鲁,則返回true。這只不過是一種性能優(yōu)化奇钞,如果比較操作有可能很昂貴澡为,就值得這么做。
2.使用instanceof操作符檢查“參數(shù)是否為正確的類型”景埃。如果不是媒至,則返回false。一般來說谷徙,所謂“正確的類型”是指equals方法所在的那個類拒啰。
3.把參數(shù)轉換成正確的類型。因為轉換之前進行過instanceof測試完慧,所以確保會成功谋旦。
4.對于該類中的每個“關鍵”域,檢查參數(shù)中的域是否與該對象中對應的域相匹配屈尼。如果這些測試全部成功册着,則返回true;否則返回false。
5.當編寫完成了equals方法之后脾歧,檢查“對稱性”甲捏、“傳遞性”、“一致性”鞭执。
3司顿、hashCode
hashCode()方法返回的就是一個數(shù)值,從方法的名稱上就可以看出兄纺,其目的是生成一個hash碼免猾。hash碼的主要用途就是在對對象進行散列的時候作為key輸入,據(jù)此很容易推斷出囤热,我們需要每個對象的hash碼盡可能不同猎提,這樣才能保證散列的存取性能。事實上,Object類提供的默認實現(xiàn)確實保證每個對象的hash碼不同(在對象的內存地址基礎上經過特定算法返回一個hash碼)锨苏。Java采用了哈希表的原理疙教。哈希(Hash)實際上是個人名,由于他提出一哈希算法的概念伞租,所以就以他的名字命名了贞谓。 哈希算法也稱為散列算法,是將數(shù)據(jù)依特定算法直接指定到一個地址上葵诈。初學者可以這樣理解裸弦,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能并不是)。
散列函數(shù),散列算法,哈希函數(shù)作喘。
是一種從任何一種數(shù)據(jù)中創(chuàng)建小的數(shù)字“指紋”的方法理疙。
散列函數(shù)將任意長度的二進制值映射為較短的固定長度的二進制值,這個小的二進制值稱為哈希值泞坦。
好的散列函數(shù)在輸入域中很少出現(xiàn)散列沖突窖贤。
=================================================================================
所有散列函數(shù)都有如下一個基本特性:
1:如果a=b,則h(a) = h(b)贰锁。
2:如果a!=b赃梧,則h(a)與h(b)可能得到相同的散列值。
Object 的hashCode方法:返回一個int類型
public native int hashCode();
3.1 hashCode的作用
想要明白豌熄,必須要先知道Java中的集合授嘀。
總的來說锣险,Java中的集合(Collection)有兩類蹄皱,一類是List,再有一類是Set囱持。前者集合內的元素是有序的夯接,元素可以重復焕济;后者元素無序纷妆,但元素不可重復。
那么這里就有一個比較嚴重的問題了:要想保證元素不重復晴弃,可兩個元素是否重復應該依據(jù)什么來判斷呢掩幢?
這就是Object.equals方法了。但是上鞠,如果每增加一個元素就檢查一次际邻,那么當元素很多時,后添加到集合中的元素比較的次數(shù)就非常多了芍阎。也就是說世曾,如果集合中現(xiàn)在已經有1000個元素,那么第1001個元素加入集合時谴咸,它就要調用1000次equals方法轮听。這顯然會大大降低效率骗露。
于是,Java采用了哈希表的原理血巍。
這樣一來萧锉,當集合要添加新的元素時,
先調用這個元素的hashCode方法述寡,就一下子能定位到它應該放置的物理位置上柿隙。
如果這個位置上沒有元素歼争,它就可以直接存儲在這個位置上傍菇,不用再進行任何比較了命爬;
如果這個位置上已經有元素了照捡,就調用它的equals方法與新元素進行比較出刷,相同的話就不存八回,不相同就散列其它的地址帖旨。所以這里存在一個沖突解決的問題找田。這樣一來實際調用equals方法的次數(shù)就大大降低了不恭,幾乎只需要一兩次叶雹。
4、eqauls方法和hashCode方法關系
Java對于eqauls方法和hashCode方法是這樣規(guī)定的:
(1)同一對象上多次調用hashCode()方法换吧,總是返回相同的整型值折晦。
(2)如果a.equals(b),則一定有a.hashCode() 一定等于 b.hashCode()沾瓦。
(3)如果!a.equals(b)满着,則a.hashCode() 不一定等于 b.hashCode()。此時如果a.hashCode() 總是不等于 b.hashCode()贯莺,會提高hashtables的性能风喇。
(4)a.hashCode()==b.hashCode() 則 a.equals(b)可真可假
(5)a.hashCode()!= b.hashCode() 則 a.equals(b)為假缕探。
上面結論簡記:
1魂莫、如果兩個對象equals,Java運行時環(huán)境會認為他們的hashcode一定相等爹耗。
2耙考、如果兩個對象不equals,他們的hashcode有可能相等潭兽。
3倦始、如果兩個對象hashcode相等,他們不一定equals山卦。
4鞋邑、如果兩個對象hashcode不相等,他們一定不equals。
關于這兩個方法的重要規(guī)范:
規(guī)范1:若重寫equals(Object obj)方法枚碗,有必要重寫hashcode()方法藻懒,確保通過equals(Object obj)方法判斷結果為true的兩個對象具備相等的hashcode()返回值。說得簡單點就是:“如果兩個對象相同视译,那么他們的hashcode應該相等”嬉荆。不過請注意:這個只是規(guī)范,如果你非要寫一個類讓equals(Object obj)返回true而hashcode()返回兩個不相等的值酷含,編譯和運行都是不會報錯的鄙早。不過這樣違反了Java規(guī)范,程序也就埋下了BUG椅亚。
規(guī)范2:如果equals(Object obj)返回false限番,即兩個對象“不相同”,并不要求對這兩個對象調用hashcode()方法得到兩個不相同的數(shù)呀舔。說的簡單點就是:“如果兩個對象不相同弥虐,他們的hashcode可能相同”。
5媚赖、為什么覆蓋equals時總要覆蓋hashCode
一個很常見的錯誤根源在于沒有覆蓋hashCode方法霜瘪。在每個覆蓋了equals方法的類中,也必須覆蓋hashCode方法惧磺。如果不這樣做的話颖对,就會違反Object.hashCode的通用約定,從而導致該類無法結合所有基于散列的集合一起正常運作磨隘,這樣的集合包括HashMap缤底、HashSet和Hashtable。
1.在應用程序的執(zhí)行期間番捂,只要對象的equals方法的比較操作所用到的信息沒有被修改个唧,那么對這同一個對象調用多次,hashCode方法都必須始終如一地返回同一個整數(shù)设预。在同一個應用程序的多次執(zhí)行過程中徙歼,每次執(zhí)行所返回的整數(shù)可以不一致。
2.如果兩個對象根據(jù)equals()方法比較是相等的絮缅,那么調用這兩個對象中任意一個對象的hashCode方法都必須產生同樣的整數(shù)結果鲁沥。
3.如果兩個對象根據(jù)equals()方法比較是不相等的呼股,那么調用這兩個對象中任意一個對象的hashCode方法耕魄,則不一定要產生相同的整數(shù)結果。但是程序員應該知道彭谁,給不相等的對象產生截然不同的整數(shù)結果吸奴,有可能提高散列表的性能。
6、總結:
1则奥、equals方法用于比較對象的內容是否相等(覆蓋以后)
2考润、hashcode方法只有在集合中用到
3、當覆蓋了equals方法時读处,比較對象是否相等將通過覆蓋后的equals方法進行比較(判斷對象的內容是否相等)糊治。
4、將對象放入到集合中時罚舱,首先判斷要放入對象的hashcode值與集合中的任意一個元素的hashcode值是否相等井辜,如果不相等直接將該對象放入集合中。如果hashcode值相等管闷,然后再通過equals方法判斷要放入對象與集合中的任意一個對象是否相等粥脚,如果equals判斷不相等,直接將該元素放入到集合中包个,否則不放入刷允。