真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中HashMap的實(shí)現(xiàn)原理是什么

這篇文章將為大家詳細(xì)講解有關(guān)Java中HashMap的實(shí)現(xiàn)原理是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對相關(guān)知識(shí)有一定的了解。

創(chuàng)新互聯(lián)公司主要從事做網(wǎng)站、成都做網(wǎng)站、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)隆回,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18982081108

一、Java中的HashCode 和equals

  • 關(guān)于hashcode

    1、hashcode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲(chǔ)結(jié)構(gòu)中確定對象的存儲(chǔ)地址的。

    2、如果兩個(gè)對象相同,就是適用于equals(java.lang.Object)方法,那么這個(gè)兩個(gè)對象的hashCode一定要相同。

    3、如果對象的equals方法被重寫,那么對象的hashCode也盡量重寫,并且產(chǎn)生hashCode使用的對象,一定要和equals方法中使用的一致,否則就會(huì)違反上面提到的第二點(diǎn)

    4、兩個(gè)對象的hashCode相同,并不一定表示兩個(gè)對象就相同,也就是不一定適用于equals(java.lang.Object)方法,只能夠說明這兩個(gè)對象在散列存儲(chǔ)結(jié)構(gòu)中,如Hashtable.他們存放在同一個(gè)籃子里

hashCode 用于查找使用的,equals是用于比較兩個(gè)對象是否相等。

  • 關(guān)于equals

    1、equals 和 ==

==用于比較引用和比較基本數(shù)據(jù)類型時(shí)具有不同的功能:

比較基本數(shù)據(jù)類型,如果兩個(gè)值相同,則結(jié)果為true

而在比較引用時(shí),如果引用指向內(nèi)存中的同一對象,結(jié)果為true;

equals()作為方法,實(shí)現(xiàn)對象的比較。由于==運(yùn)算符不允許我們進(jìn)行覆蓋,也就是說它限制了我們的表達(dá)。因此我們復(fù)寫(重寫,子類復(fù)寫)equals方法,達(dá)到比較對象內(nèi)容是否相同的目的。而這些通過==運(yùn)算符是做不到的。

    2、Object類的equals()方法的比較規(guī)則為:如果兩個(gè)對象的類型一致,并且內(nèi)容一致,則返回true,這些類有:

java.io.file,java.util.Date,java.lang.string,包裝類(Integer,Double等)

二、HashMap的實(shí)現(xiàn)原理

1、HashMap概述

HashMap是基于哈希表的Map接口的非同步實(shí)現(xiàn)。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恒久不變。

在Java編程語言中,最基本的結(jié)構(gòu)就是兩種,一種是數(shù)組,另一個(gè)是模擬指針(引用),所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本結(jié)構(gòu)來構(gòu)造,HashMap也不列外。HashMap也不例外。HashMap實(shí)際上是一個(gè)鏈表散列的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。

Java中HashMap的實(shí)現(xiàn)原理是什么

從上圖中可以看出,HashMap底層就是一個(gè)數(shù)組結(jié)構(gòu),數(shù)組中的每一項(xiàng)又是一個(gè)鏈表。當(dāng)新建一個(gè)HashMap的時(shí)候,就會(huì)初始化一個(gè)數(shù)組。

/**
 * Basic hash bin node, used for most entries.  (See below for
 * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
 */
static class Node implements Map.Entry {
    final int hash;
    final K key;
    V value;
    Node next;

    Node(int hash, K key, V value, Node next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }

    public final K getKey()        { return key; }
    public final V getValue()      { return value; }
    public final String toString() { return key + "=">可以看出,Node就是數(shù)組中的元素,每個(gè) Map.Entry 其實(shí)就是一個(gè)key-value對,它持有一個(gè)指向下一個(gè)元素的引用,這就構(gòu)成了鏈表 2、HashMap實(shí)現(xiàn)存儲(chǔ)和讀取1)存儲(chǔ)/**
 * Associates the specified value with the specified key in this map.
 * If the map previously contained a mapping for the key, the old
 * value is replaced.
 *
 * @param key key with which the specified value is to be associated
 * @param value value to be associated with the specified key
 * @return the previous value associated with key, or
 *         null if there was no mapping for key.
 *         (A null return can also indicate that the map
 *         previously associated null with key.)
 */
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

/**
 * Implements Map.put and related methods
 *
 * @param hash hash for key
 * @param key the key
 * @param value the value to put
 * @param onlyIfAbsent if true, don't change existing value
 * @param evict if false, the table is in creation mode.
 * @return previous value, or null if none
 */
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;
        else if (p instanceof TreeNode)
            e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
} 根據(jù)hash值得到這個(gè)元素在數(shù)組中的位置(即下標(biāo)),如果數(shù)組該位置上已經(jīng)存放有其他元素了,那么在這個(gè)位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果數(shù)組該位置上沒有元素,就直接將該元素放到此數(shù)組中的該位置上。/**
 * Computes key.hashCode() and spreads (XORs) higher bits of hash
 * to lower.  Because the table uses power-of-two masking, sets of
 * hashes that vary only in bits above the current mask will
 * always collide. (Among known examples are sets of Float keys
 * holding consecutive whole numbers in small tables.)  So we
 * apply a transform that spreads the impact of higher bits
 * downward. There is a tradeoff between speed, utility, and
 * quality of bit-spreading. Because many common sets of hashes
 * are already reasonably distributed (so don't benefit from
 * spreading), and because we use trees to handle large sets of
 * collisions in bins, we just XOR some shifted bits in the
 * cheapest possible way to reduce systematic lossage, as well as
 * to incorporate impact of the highest bits that would otherwise
 * never be used in index calculations because of table bounds.
 */
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} 我們可以看到在hashMap中要找到某個(gè)元素,需要根據(jù)key的hash值來求得對應(yīng)數(shù)組中的位置。如何計(jì)算這個(gè)位置就是hash算法。前面的說過HashMap的數(shù)據(jù)結(jié)構(gòu)是數(shù)組和鏈表的結(jié)合,所以我們希望這個(gè)HashMap里面的元素位置盡量的分布均勻些。盡量使得每個(gè)位置上的元素?cái)?shù)量只有一個(gè),那么當(dāng)我們用hash算法求得這個(gè)位置時(shí),馬上就可以知道對應(yīng)位置的元素都是我們要的,而不用再去遍歷鏈表,這就大大優(yōu)化了查詢效率。HashMap 在底層將 key-value 當(dāng)成一個(gè)整體進(jìn)行處理,這個(gè)整體就是一個(gè) Node 對象。HashMap 底層采用一個(gè) Node[] 數(shù)組來保存所有的 key-value 對,當(dāng)需要存儲(chǔ)一個(gè) Node 對象時(shí),會(huì)根據(jù)hash算法來決定其在數(shù)組中的存儲(chǔ)位置,在根據(jù)equals方法決定其在該數(shù)組位置上的鏈表中的存儲(chǔ)位置;當(dāng)需要取出一個(gè)Entry時(shí),也會(huì)根據(jù)hash算法找到其在數(shù)組中的存儲(chǔ)位置,再根據(jù)equals方法從該位置上的鏈表中取出該Node。3、HashMap的resize    當(dāng)hashmap的元素越來越多的時(shí)候,碰撞的概率就越來越高(因?yàn)閿?shù)組的長度是固定的),所以為了提高查詢的效率,就要對hashMap的數(shù)組進(jìn)行擴(kuò)容,數(shù)組擴(kuò)容這個(gè)操作也會(huì)出現(xiàn)在ArrayList中,所以這是一個(gè)通用的操作,類似均攤。hashmap擴(kuò)容之后,最消耗性能的點(diǎn)就出現(xiàn)了:原數(shù)組中的數(shù)據(jù)必須重新計(jì)算其在新數(shù)組中的位置,并放進(jìn)去,就是resize。    那么hashmap什么時(shí)候擴(kuò)容?當(dāng)hashmap中的元素個(gè)數(shù)超過數(shù)組大小*loadFactor時(shí),就會(huì)進(jìn)行數(shù)組擴(kuò)容,loadFactor的默認(rèn)值為0.75,也就是說,默認(rèn)情況下,數(shù)組大小為16,那么當(dāng)hashmap中元素個(gè)數(shù)超過16*0.75=12的時(shí)候,就把數(shù)組的大小擴(kuò)展為2*16=32,即擴(kuò)大一倍,然后重新計(jì)算每個(gè)元素在新數(shù)組中的位置,放進(jìn)去,就是resize??偨Y(jié):HashMap的實(shí)現(xiàn)原理:    1、實(shí)現(xiàn)key的hashCode重新hash計(jì)算出當(dāng)前對象的元素在數(shù)組中的下標(biāo)。    2、存儲(chǔ)時(shí),如果出現(xiàn)hash值相同的key,此時(shí)有兩種情況。(1)如果key相同,則覆蓋原始值;(2)如果key不同(出現(xiàn)沖突),則將當(dāng)前的key-value放入鏈表中    3、獲取時(shí),直接找hash值對應(yīng)的下標(biāo),在進(jìn)一步判斷key是否相同,從而找到對應(yīng)值。    4、理解以上過程就不難明白HashMap是如何解決hash沖突的問題,核心就是使用了數(shù)組的存儲(chǔ)方式,然后將沖突的key的對象放入鏈表中,一旦發(fā)現(xiàn)沖突就在鏈表中做進(jìn)一步的對比。

關(guān)于Java中HashMap的實(shí)現(xiàn)原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。


新聞標(biāo)題:Java中HashMap的實(shí)現(xiàn)原理是什么
網(wǎng)址分享:http://weahome.cn/article/peodch.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部