摘要:如果根據方法得到兩個對象不相同,那么兩個對象的方法的結果不一定不相同,我們可以利用這一點來提高散列表的性能。最后回到文章開頭的問題,如何判斷兩個對象或值是否相同這個問題其實有兩方面的含義,一方面是判斷的方法,另一方面是判斷的效率。
Java中有很多場景需要判斷兩個對象或者兩個值,那么
判斷是否相同的依據是什么?
如何判斷是否相同呢?
為了解釋這個問題,我們從Java語言的根說起,那Java語言的根在哪里?我們知道Java是一種面向對象的編程語言,對象是類的實例,所有的類都隱式繼承Object類,那Object類就是所有類的父類,也就是我們所說的根。
Object類中方法不多,其中有兩個方法,一個叫equals,另一個叫hashCode;
JDK中對equals的定義是:
Indicates whether some other object is "equal to" this one.
意思是說equals方法是用來判斷兩個對象是否相同的,到這里是不是已經得到了文章開始的問題答案了呢,其實只能說得到了三分之一的答案,再看equals方法的實現,
public boolean equals(Object obj) { return (this == obj); }
代碼很簡單,通過“== ”判斷兩個對象是否相同;這里就要解釋一下Java中“== ”符號的作用,文章開頭也說了Java是一種面向對象的編程語言,所以Java中全都是對象,這樣表述是否正確呢?應該算不完全正確,因為Java中還有一類基本數據類型,比如byte、short、int、long、float、double、boolean;當“== ”符號作用于基本數據類型時,其比較的是值,當==符號作用于類對象時其比較的是對象在堆內存的地址。
顯然Object類的equals方法適用的是類對象;也就是equals比較的是對象的堆內存地址,如果自定義的類不重寫Object的equals方法,那么比較這個類的兩個對象相當于比較這兩個對象的堆內存地址,實際情況是,很多自定義的類對象的比較并不想通過判斷對象的堆內存地址判斷兩個對象是否相同,而需要定義一些符合業務需求的規則,也就是說需要重寫equals方法;比如String類就重寫了Object的equals方法,
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
說了半天都是在說equals方法,開頭還提到了hashCode方法,hashCode方法有什么作用呢?
Object類的hashCode方法定義如下,可以看出其是一個本地方法,該方法的解釋是“Returns a hash code value for the object.”
public native int hashCode();
hashCode方法的定義中描述了其general contract:
相同的對象每次執行hashCode的結果是相同的,這里的相等是指通過equals比較相同。
如果根據equals方法得到兩個對象相同,那么這兩個對象的hashCode方法的結果也一定相同。
如果根據equals方法得到兩個對象不相同,那么兩個對象的hashCode方法的結果不一定不相同,我們可以利用這一點來提高散列表的性能。
hashCode方法的定義還有一句話:This method is supported for the benefit of hash tables such as those provided by {@link java.util.HashMap}.
這句話什么意思呢?直白一點就是hashCode方法只有在散列表中才有作用;那什么是散列表?下面是維基百科的定義:
In computing, a hash table (hash map) is a data structure that implements an associative array abstract data type, a structure that can map keys to values. A hash table uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found.
散列表是一個以空間換時間的數據結構,通過key查找value,通過一個計算hash值的函數得到每個key在結構中的位置索引,通過位置索引能夠快速定位value。HashMap是Java語言中散列表的一種實現,下面是HashMap的hash方法和put方法的源碼,
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
可以看到在計算key的散列值時,用到了key的hashCode方法。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node[] tab; Node p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; ... }
當網map中放值時,如果key的hash值相等時,用equals方法判斷key是否相等,如果相等說明key在map中存在,則用新的value替換當前的value。說了這么多,到底想說明什么?我們反過來思考一下,如果沒有hashCode方法,我們判斷某個鍵是否已經存在,要通過equals方法逐個比較這個key和map中的所有key,數據量小的情況下是可以接受的,如果數據量大,這個比較的開銷是難以接受的,這就體現出了hashCode的作用,不需要和map中所有的key逐個比較,只需要比較hash值相同的即可,大大減少了比較的時間。這里即用到了key的equals方法又用到了hashCode方法,如果自定義類按照業務邏輯重寫了equals方法,但沒有按照類似的邏輯重寫hashCode方法,key值是否重復的判斷結果就會有問題,所以一般情況下如果重寫了equals方法,一定要重寫hashCode方法。
最后回到文章開頭的問題,如何判斷兩個對象或值是否相同?這個問題其實有兩方面的含義,一方面是判斷的方法,另一方面是判斷的效率。
判斷的方法:equals方法和符號“== ”,分別用于對象和基本數據類型。
在需要判斷的數據量很大的情況下,用equals方法逐個比較效率是很低的,這時候hashCode方法就派上用場了,hashCode方法的定義決定了其一些特性,相同對象的hashCode方法返回的值是相等的,不同的對象的hashCode方法返回值不一定不相同,所以通過hashCode方法能夠大大縮小比較的范圍,提高比較的效率。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76608.html
摘要:一流轉換為數組集合陳楊將流轉換為數組將流轉換為數組將流轉換為集合將流轉換為集合解析 一、流 轉換為數組、集合 package com.java.design.java8.Stream; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context...
摘要:而漸進增強和優雅降級兩種不同的開發流程,也是在我們項目初期做調研選型時會考慮的一個點。二者區別漸進增強和優雅降級只是看待同種事物的兩種觀點。漸進增強和優雅降級都關注于同一網站在不同設備里不同瀏覽器下的表現程度。 作為一名前端開發人員,最頭疼的莫過于瀏覽器兼容。遠古時期萬惡的IE6,到現在CSS3不兼容的IE7/8.為了保證不同版本瀏覽器都有共同或更優化的用戶體驗,前端搬磚的我們不得不與...
摘要:而漸進增強和優雅降級兩種不同的開發流程,也是在我們項目初期做調研選型時會考慮的一個點。二者區別漸進增強和優雅降級只是看待同種事物的兩種觀點。漸進增強和優雅降級都關注于同一網站在不同設備里不同瀏覽器下的表現程度。 作為一名前端開發人員,最頭疼的莫過于瀏覽器兼容。遠古時期萬惡的IE6,到現在CSS3不兼容的IE7/8.為了保證不同版本瀏覽器都有共同或更優化的用戶體驗,前端搬磚的我們不得不與...
摘要:而漸進增強和優雅降級兩種不同的開發流程,也是在我們項目初期做調研選型時會考慮的一個點。二者區別漸進增強和優雅降級只是看待同種事物的兩種觀點。漸進增強和優雅降級都關注于同一網站在不同設備里不同瀏覽器下的表現程度。 作為一名前端開發人員,最頭疼的莫過于瀏覽器兼容。遠古時期萬惡的IE6,到現在CSS3不兼容的IE7/8.為了保證不同版本瀏覽器都有共同或更優化的用戶體驗,前端搬磚的我們不得不與...
閱讀 1170·2021-11-22 15:24
閱讀 4445·2021-09-23 11:51
閱讀 2307·2021-09-08 09:36
閱讀 3521·2019-08-30 15:43
閱讀 1301·2019-08-30 13:01
閱讀 1121·2019-08-30 12:48
閱讀 544·2019-08-29 12:52
閱讀 3372·2019-08-29 12:41