《Thinking in Java》學(xué)習(xí)——17章容器深入研究(二)

理解Map

1.映射表的基本思想是它維護(hù)的是鍵-值(對(duì))關(guān)聯(lián),因此你可以使用鍵來(lái)查找值。
2.下面是一個(gè)簡(jiǎn)單的關(guān)聯(lián)數(shù)組的創(chuàng)建:

public class AssociativeArray<K, V> {
    private Object[][] pairs;
    private int index;
    public AssociativeArray(int length) {
        pairs = new Object[length][2];
    }
    public void put(K key, V value) {
        if (index >= pairs.length) 
            throws new ArrayIndexOutOfBoundsException();
        pairs[index++] = new Object[]{key, value};
    }
    @SupressWarning("unchecked")
    public V get(K key) {
        for (int i = 0; i < pairs.length; i++) {
            if (key.equals(pairs[i][0])) {
                return (V) pairs[i][1];
            }
        }
        return null;
    }
}

上面的代碼只是具有一定的說(shuō)明性,但是缺乏效率,并且由于具有固定尺寸而顯得很不靈活。

一.性能

1.HashMap使用了特殊的值,稱為散列碼,來(lái)取代對(duì)鍵的緩慢搜索。散列碼是相對(duì)唯一的、用以代表對(duì)象的int值,他是通過(guò)將該對(duì)象的某些信息進(jìn)行轉(zhuǎn)換而生成的。
2.hashCode()是類Object中的方法,因此所有Java對(duì)象都能產(chǎn)生散列碼。HashMap就是使用對(duì)象的hashCode()進(jìn)行快速查詢的,此方法能夠顯著提高性能。
3.下面是幾種基本的Map的實(shí)現(xiàn):

Method 實(shí)現(xiàn)描述
HashMap Map基于散列表帶你實(shí)現(xiàn)(它取代了Hashtable)。插入和查詢“鍵值對(duì)”的開銷是固定的。可以通過(guò)構(gòu)造器設(shè)置容量和負(fù)載因子,以調(diào)整容器的性能
LinkedHashMap 類似于HashMap,但是便利它時(shí),取得“鍵值對(duì)”的順序是其插入順序,或是最近最少使用的順序。只比HashMap慢一點(diǎn);而在迭代訪問(wèn)時(shí)反而更快,因?yàn)樗褂面湵砭S護(hù)內(nèi)部的次序
TreeMap 基于紅黑樹的實(shí)現(xiàn)。查看“鍵”或“鍵值對(duì)”時(shí),它們會(huì)被排序(由ComparableComparator決定)。TreeMap的特定在于,所得到的結(jié)果是經(jīng)過(guò)排序的。TreeMap是唯一的帶有subMap()方法的Map。它可以返回一個(gè)子樹
WeekHashMap 弱鍵映射,允許釋放映射所指向的對(duì)象;這是為解決某類特殊問(wèn)題而設(shè)計(jì)的。如果映射之外沒有引用指向某個(gè)“鍵”,則此“鍵”可以被垃圾回收器回收
ConcurrentHashMap 一種線程安全的Map,它不涉及同步加鎖
IdentityHashMap 使用==代替equals()對(duì)“鍵”進(jìn)行比較的散列映射。

4.對(duì)Map中使用的鍵的要求與對(duì)Set中的元素的要求一樣。任何鍵都必須具有一個(gè)equals()方法;如果鍵被用于散列Map,那么它必須還具有恰當(dāng)?shù)?strong>hashCode()方法;如果鍵被用于TreeMap,那么它必須實(shí)現(xiàn)Comparable。
5.關(guān)聯(lián)數(shù)組中的基本方法是put()get()。keySet()方法返回一個(gè)由Map的鍵組成的Set??梢灾苯油ㄟ^(guò)values()方法獲取“值”,該方法會(huì)產(chǎn)生一個(gè)包含Map中所有“值”的Collection,需要注意的是對(duì)該Collection的任何改動(dòng)都會(huì)反映到與之相關(guān)聯(lián)的Map

二.SortedMap

1.使用SortedMapTreeMap是其現(xiàn)階段的唯一實(shí)現(xiàn)),可以確?!版I”處于排序狀態(tài)。
2.SortedMap接口中的一些特殊方法如下:

Method 功能描述
Comparator comparator() 返回當(dāng)前Map使用的Comparator;或者返回null,表示以自然方式排序
T firstKey() 返回Map中的第一個(gè)鍵
T lastKey() 返回Map中的最末一個(gè)鍵
SortedMap subMap(fromKey, toKey) 生成此Map的子集,范圍由fromKey(包含)到toKey(不包含)的鍵確定
SortedMap headMap(toKey) 生成此Map的子集,由小于toKey的所有鍵值對(duì)確定
SortedMap tailMap(fromKey) 生成此Map的子集,由大于或等于fromMap的所有鍵值對(duì)組成
三.LinkedHashMap

1.為了提高速度,LinkedHashMap散列化所有的元素,但是在遍歷鍵值對(duì)時(shí),卻又以元素的插入順序返回鍵值對(duì)。
2.可以在構(gòu)造器中設(shè)定LinkedHashMap,使之采用基于訪問(wèn)的最近最少使用算法。于是沒有被訪問(wèn)過(guò)的元素酒會(huì)出現(xiàn)在隊(duì)列的最前面。對(duì)于需要定期清理元素以節(jié)省空間的程序來(lái)說(shuō),此功能使得程序很容易就能實(shí)現(xiàn)。

散列與散列碼

1.使用標(biāo)準(zhǔn)類庫(kù)中的類來(lái)作為HashMap的鍵沒有問(wèn)題,因?yàn)樗邆淞随I所需的全部性質(zhì)。
2.當(dāng)自己創(chuàng)建用作HashMap的鍵的類,有可能會(huì)忘記在其中放置必需的方法,而這是通常會(huì)犯的一個(gè)錯(cuò)誤。
3.可能你會(huì)認(rèn)為,只需編寫恰當(dāng)?shù)?strong>hashCode()方法的覆蓋版本即可。但是它仍然無(wú)法正常運(yùn)行,除非你同時(shí)覆蓋equals()方法,它也是Object的一部分。HashMap使用equals()判斷當(dāng)前的鍵是否與表中的相同。
4.正確的equals()方法必須滿足的條件:
(1)自反性。對(duì)任意x,x.equals(x)一定返回true。
(2)對(duì)稱性。對(duì)任意xy,如果y.equals(x)返回true,則x.equals(y)一定返回true。
(3)傳遞性。對(duì)任意x,yz,如果有x.equals(y)返回truey.equals(z)返回true,則x.equals(z)一定返回true。
(4)一致性。對(duì)任意xy,如果對(duì)象中用于等價(jià)比較的信息沒有改變,那么無(wú)論調(diào)用x.equals(y)多少次,返回的結(jié)果應(yīng)該保持一致,要么一直是true要么一直是false。
(5)對(duì)任何不是nullx,x.equals(null)一定返回false。

一.理解hashCode()

1.使用散列的目的是:想要試用一個(gè)對(duì)象來(lái)查找另外一個(gè)對(duì)象。

二.為速度而散列

1.散列的價(jià)值在于速度:散列使得查詢得以快速進(jìn)行。
2.散列將鍵保存在某處,以便能夠快速找到。存儲(chǔ)一組元素最快的數(shù)據(jù)結(jié)構(gòu)是數(shù)組嗎所以使用它來(lái)表示鍵的信息。
3.數(shù)組并不保存鍵本身。而是通過(guò)鍵對(duì)象生成一個(gè)數(shù)字,將其作為數(shù)組的下標(biāo)。這個(gè)數(shù)字就是散列碼,由hashCode()方法生成。
4.為解決數(shù)組容量被固定的問(wèn)題,不同的鍵會(huì)產(chǎn)生相同的下標(biāo)。也就是說(shuō),可能會(huì)有沖突。因此,數(shù)組多大就不重要了,任何鍵總能在數(shù)組中找到它的位置。
5.查詢一個(gè)值的過(guò)程首先就是計(jì)算散列碼,然后使用散列碼查詢數(shù)組。如果能夠沒有沖突,那就有了一個(gè)完美的散列函數(shù),但這只是特例。通常。沖突由外部鏈接處理:數(shù)組并不直接保存值,而是保存值的list。然后對(duì)list中的值使用equals()方法進(jìn)行線性查詢。這部分的查詢自然會(huì)比較慢,但是,如果散列函數(shù)好的話,數(shù)組的每個(gè)位置就只有較少的值。因此,不會(huì)查詢整個(gè)list,而是快速地跳到數(shù)組的某個(gè)位置,只對(duì)很少的元素進(jìn)行比較。

三.覆蓋hashCode()

1.在使用HashMap的時(shí)候,你無(wú)法控制數(shù)組的下標(biāo)值的產(chǎn)生。這個(gè)值依賴于具體的HashMap對(duì)象的容量,而容量大改變與容器的充滿程度和負(fù)載因子有關(guān)。
2.設(shè)計(jì)hashCode()最重要的一個(gè)因素:無(wú)論何時(shí),對(duì)同一個(gè)對(duì)象調(diào)用hashCode()都應(yīng)該產(chǎn)生同樣的值。
3.不應(yīng)該使hashCode()依賴于具有唯一性的對(duì)象信息,尤其是使用this的值。因?yàn)檫@樣做無(wú)法生成一個(gè)新的鍵,使之與put()中原始的鍵值對(duì)中的鍵相同。
4.hashCode()必須基于對(duì)象的內(nèi)容生成散列碼。散列碼不鄙視獨(dú)一無(wú)二的,但是通過(guò)hashCode()equals(),必須能夠完全確定對(duì)象的身份。
5.好的hashCode()應(yīng)該產(chǎn)生分布均勻的散列碼。如果散列碼都集中在一塊,那么HashMap或者HashSet在某些區(qū)域的負(fù)載會(huì)很重,這樣就不如分布均勻的散列函數(shù)快。
6.產(chǎn)生hashCode()的基本指導(dǎo):
(1)給int變量result賦予某個(gè)非零值常量,例如17。
(2)為對(duì)象內(nèi)每一個(gè)有意義的域f(即每個(gè)可以做equals()操作的域)計(jì)算出一個(gè)int散列碼c

域類型 計(jì)算
boolean c = (f ? 0 : 1)
byte、char、shortint c = (int)f
long c = (int) (f ^ (f >>> 32))
float c = Float.floatToBits(f)
double long l = Double.doubleToLongBits(f) c = (int) (l ^ l >>> 32)
Object,其equals()調(diào)用這個(gè)域的equals() c = f.hashCode()
數(shù)組 對(duì)每個(gè)元素應(yīng)用上面的規(guī)則

(3)合并計(jì)算得到的散列碼:
result = 37 * result + c;
(4)返回result。
(5)檢查hashCode()最后生成的結(jié)果,確保相同的對(duì)象有相同的散列碼。
7.compareTo()的創(chuàng)建方式:排序的規(guī)則首先按照實(shí)際類型排序,然后如果有名字的話,按照name排序,最后安好創(chuàng)建的順序排序。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,223評(píng)論 0 16
  • 一、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對(duì)于byte類型而言...
    龍貓小爺閱讀 4,443評(píng)論 0 16
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,644評(píng)論 18 399
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,895評(píng)論 0 11
  • 附記南遷得失 或問(wèn)南遷得失何如?予應(yīng)之曰:當(dāng)自成逾秦入晉,勢(shì)已破竹,惟南遷一策,或可稍延歲月,而光時(shí)亨以為邪說(shuō),其...
    隴右雷柯柯閱讀 223評(píng)論 0 1

友情鏈接更多精彩內(nèi)容