成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Java容器】HashMap使用方法及源碼分析

ad6623 / 1481人閱讀

摘要:當(dāng)哈希表中的鍵值對(duì)的數(shù)量超過當(dāng)前容量與負(fù)載因子的乘積時(shí),哈希表將會(huì)進(jìn)行操作,使哈希表的桶數(shù)增加一倍左右。只有散列值相同且相同才是所要找的節(jié)點(diǎn)。

HashMap容器 1. 簡(jiǎn)介

HashMap基于散列表實(shí)現(xiàn)了Map接口,提供了Map的所有可選操作,HashMap與Hashtable大致相同,區(qū)別在于HashMap不支持同步而且HashMap中存儲(chǔ)的鍵值都可以為null。HashMap中不保證散列表的順序。

當(dāng)散列函數(shù)將元素正確地分散到各個(gè)桶之中的時(shí)候,HashMap中存取操作的時(shí)間復(fù)雜度都是O(1)。當(dāng)HashMap實(shí)例的容量(capacity)為M,存儲(chǔ)的鍵值對(duì)的數(shù)量(size)為N時(shí),遍歷HashMap的時(shí)間復(fù)雜度為O(M+N)。

影響一個(gè)HashMap實(shí)例的性能的兩個(gè)參數(shù)分別是:initial capacity(初始容量)load factor(負(fù)載因子)。容量表示哈希表中桶的個(gè)數(shù),初始容量就是HashMap實(shí)例在構(gòu)造化時(shí)初始化的容量;負(fù)載因子則控制哈希表在多滿的時(shí)候需要自動(dòng)擴(kuò)容。當(dāng)哈希表中的鍵值對(duì)(entry)的數(shù)量超過當(dāng)前容量與負(fù)載因子的乘積時(shí),哈希表將會(huì)進(jìn)行rehash操作,使哈希表的桶數(shù)增加一倍左右。

一般默認(rèn)的負(fù)載因子取0.75,可以較好地平衡時(shí)間與空間花費(fèi)。過高的負(fù)載因子雖然節(jié)省空間,但是增加了訪問哈希表的時(shí)間消耗。在設(shè)置初始容量時(shí)需要考慮散列表中期望存放的鍵值對(duì)數(shù)量以及負(fù)載因子,減少rehash的次數(shù)。

2. 方法 2.1 構(gòu)造方法

HashMap的構(gòu)造方法共有四種重載形式,可以在構(gòu)造時(shí)指定HashMap的初始容量、負(fù)載因子或者使用已有的HashMap來初始化新的HashMap。

HashMap map1 = new HashMap<>();    // 創(chuàng)建空的HashMap,默認(rèn)容量16,默認(rèn)負(fù)載因子0.75
System.out.println(map1);    // {}
        
int cap = 50;
HashMap map2 = new HashMap<>(cap);    // 創(chuàng)建空的HashMap,初始化容量為cap,默認(rèn)負(fù)載因子0.75
System.out.println(map2);    // {}
        
float lf = 0.5f;
HashMap map3 = new HashMap<>(cap, lf);    // 創(chuàng)建空的HashMap,初始化容量為cap,默認(rèn)負(fù)載因子lf
System.out.println(map3);    // {}
        
HashMap map4 = new HashMap<>(map3);    // 使用另一個(gè)HashMap來創(chuàng)建一個(gè)新的HashMap
System.out.println(map4);    // {}
System.out.println("map4 == map3? "+(map4 == map3));    // 不是同一個(gè)HashMap對(duì)象
System.out.println("map4.equals(map3)? "+(map4.equals(map3)));    // HashMap中的內(nèi)容相等
2.2 添加元素

HashMap提供put(K key, V value) 、putAll(Map m)

以及putIfAbsent(K key, V value)方法向HashMap添加單個(gè)鍵值對(duì)或添加指定HashMap中的所有鍵值對(duì)。

map1.put("a", 100);    // 添加{k:v}記錄
System.out.println("map1:"+map1);    // map1:{a=100}
        
map2.putAll(map1);    // 復(fù)制另一個(gè)HashMap的所有鍵值對(duì)
System.out.println("map2:"+map2);    // map2:{a=100}
        
int ret1 = map1.putIfAbsent("a", 200);    // 嘗試添加記錄{k:v},若k已存在且指向非null,返回當(dāng)前HashMap的k所指對(duì)象
System.out.println("map1:"+map1+" return:"+ret1);    // map1:{a=100} return:100
Object ret2 = map1.putIfAbsent("b", 200);    // 若k不存在或指向null,添加{k:v}記錄,返回null
System.out.println("map1:"+map1+" return:"+ret2);    // map1:{a=100, b=200} return:null
2.3 刪除元素

HashMap提供重載的remove()方法刪除HashMap中的鍵值對(duì)。

int ret3 = map1.remove("a");    // 根據(jù)指定的鍵刪除一個(gè)鍵值對(duì)
System.out.println("map1:"+map1+" return:"+ret3);    // map1:{b=200} return:100
        
boolean ret4 = map1.remove("b", 300);    // 刪除指定的鍵值對(duì),若k不指向v,則不刪除,返回是否成功刪除
System.out.println("map1:"+map1+" return:"+ret4);    // map1:{b=200} return:false
boolean ret5 = map1.remove("b", 200);
System.out.println("map1:"+map1+" return:"+ret5);    // map1:{} return:true
2.4 訪問元素

HashMap提供get(Object key)getOrDefault(Object key, V defaultValue)獲取指定鍵對(duì)應(yīng)的值,若HashMap中無該鍵的記錄,前者返回null后者返回默認(rèn)值。

int val1 = map2.get("a");    // 獲取指定鍵的值,若無記錄返回null
System.out.println("map2:"+map2+" a:"+val1);    // map2:{a=100} a:100
        
int val2 = map2.getOrDefault("b", 200);    // 獲取指定鍵的值,若無記錄則返回指定值
System.out.println("map2:"+map2+" b:"+val2);    // map2:{a=100} b:200
2.5 元素變更

HashMap提供重載的replace()方法,用于更新HashMap中指定的鍵值對(duì)。

int ret6 = map2.replace("a", 300);    // 更新HashMap中存在的某個(gè)鍵對(duì)應(yīng)的值,返回更新前的值
System.out.println("map2:"+map2+" return:"+ret6);    // map2:{a=300} return:100
Object ret7 = map2.replace("c", 300);    // 更新HashMap中某個(gè)鍵的值,若無該鍵的記錄,直接返回null
System.out.println("map2:"+map2+" return:"+ret7);    // map2:{a=300} return:null
        
boolean ret8 = map2.replace("a", 300, 400);    // 更新HashMap中存在的指定鍵值對(duì),返回操作是否成功
System.out.println("map2:"+map2+" return:"+ret8);    // map2:{a=400} return:true
boolean ret9 = map2.replace("a", 100, 200);    // 指定的鍵值對(duì)不對(duì)應(yīng)
System.out.println("map2:"+map2+" return:"+ret9);    // map2:{a=400} return:false
boolean ret10 = map2.replace("b", 100, 200);    // 無指定的鍵
System.out.println("map2:"+map2+" return:"+ret10);    // map2:{a=400} return:false

// void replaceAll(BiFunction function)
2.6 HashMap操作

clear()方法用于刪除所有元素;

isEmpty()方法檢查HashMap是否為空;

size()方法返回HashMap中鍵值對(duì)的數(shù)量;

containsKey(Object key)方法檢查HashMap中是否有指定的鍵的記錄;

containsKey(Object value)方法檢查HashMap中是否有指定的值的記錄;

boolean ret11 = map1.containsKey("a");    // 檢查HashMap中是否有指定的鍵的記錄
System.out.println("map1:"+map1+" return:"+ret11);    // map1:{a=100, b=200, c=100} return:true
boolean ret12 = map1.containsKey("d");
System.out.println("map1:"+map1+" return:"+ret12);    // map1:{a=100, b=200, c=100} return:false

boolean ret13 = map1.containsValue(100);    // 檢查HashMap中是否有指定的值的記錄
System.out.println("map1:"+map1+" return:"+ret13);    // map1:{a=100, b=200, c=100} return:true
boolean ret14 = map1.containsValue(500);
System.out.println("map1:"+map1+" return:"+ret14);    // map1:{a=100, b=200, c=100} return:false

entrySet()方法以Set的形式返回HashMap中的每個(gè)鍵值對(duì)(Entry);

Set ret15 = map1.entrySet();    // 以Set的形式返回HashMap中的每個(gè)鍵值對(duì)(Entry)
System.out.println("map1:"+map1+" 
Set:"+ret15);
// map1:{a=100, b=200, c=100}
// Set:[a=100, b=200, c=100]

keySet()方法以Set的形式返回HashMap中的每個(gè)鍵;

Set ret17 = map1.keySet();    // 以Set的形式返回HashMap中的每個(gè)鍵
System.out.println("map1:"+map1+" 
Set:"+ret17);
// map1:{a=100, b=200, c=100} 
// Set:[a, b, c]

values()方法以Collection的形式返回HashMap中的值。

Collection ret19 = map1.values();    // 以Collection的形式返回HashMap中的值
System.out.println("map1:"+map1+" 
Collection:"+ret19);
// map1:{a=100, b=200, c=100} 
// Collection:[100, 200, 100]
3. 源碼分析

版本:jdk 1.8

3.1 存儲(chǔ)結(jié)構(gòu)

HashMap中使用一個(gè)數(shù)組存儲(chǔ)鍵值對(duì)(Node),數(shù)組的大小默認(rèn)為16,且只能為2的整數(shù)次冪。

/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node[] table;

每個(gè)Node中記錄四個(gè)字段,

 static class Node implements Map.Entry {
        final int hash;
        final K key;
        V value;
        Node next;
        ...
}
3.2 put()方法

put(K key, V value)方法向HashMap中添加一個(gè)鍵值對(duì),

    /**
     * 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.
     * ...
     */
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

其會(huì)對(duì)輸入的key調(diào)用hash()方法,再調(diào)用putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)方法實(shí)現(xiàn),

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node[] tab; Node p; int n, i;
        /*判斷是否需要擴(kuò)容,若需要?jiǎng)t擴(kuò)容,最后得到HashMap的當(dāng)前容量*/
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        /*計(jì)算新添加條目在散列表的位置,若hash值沒發(fā)生沖突,直接添加新條目*/
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        /*hash值沖突*/
        else {
            Node e; K k;
            /*若新添加的條目的key與已有的key相同,則覆蓋*/
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            /*若該桶中已經(jīng)是樹結(jié)構(gòu),添加條目到該樹中*/
            else if (p instanceof TreeNode)
                e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
            /*新條目與舊條目hash值相同,key不同的情況(采用拉鏈法)*/
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);    // 新條目插在鏈表末端
                        /*若鏈表長(zhǎng)度大于等于8時(shí),轉(zhuǎn)換為樹結(jié)構(gòu)*/
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    /*若新添加的條目的key與鏈表中已有的key相同,則覆蓋*/
                    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;
            }
        }
        /*記錄操作次數(shù)*/
        ++modCount;
        /*添加條目后再檢查是否需要resize*/
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

在插入新條目的時(shí)候,首先根據(jù)key計(jì)算出散列值,然后根據(jù)散列值確定條目存放的桶的下標(biāo),

i = (n - 1) & hash    // i為桶的索引,n為桶的數(shù)量

如果該位置為空,則直接存放新條目;如果不為空,則在該位置使用鏈表記錄這些相同散列值的條目,當(dāng)一個(gè)桶記錄的條目大于8時(shí),改用紅黑樹記錄該桶中的元素。

3.3 get()方法

get(Object key)方法根據(jù)指定的key返回一個(gè)value,

    public V get(Object key) {
        Node e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

調(diào)用了getNode(int hash, Object key)方法,獲取指定key的節(jié)點(diǎn)(Entry),

    final Node getNode(int hash, Object key) {
        Node[] tab; Node first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                /*在紅黑樹結(jié)構(gòu)中搜索節(jié)點(diǎn)*/
                if (first instanceof TreeNode)
                    return ((TreeNode)first).getTreeNode(hash, key);
                /*在鏈表中搜索節(jié)點(diǎn)*/
                do {
                    /*分別比較散列值和key是否相同*/
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

在尋找指定key的節(jié)點(diǎn)時(shí),會(huì)先比較散列值是否相同,再比較key的值是否相同。只有key散列值相同且key相同才是所要找的節(jié)點(diǎn)。

3.4 remove()方法

remove()方法,

    @Override
    public boolean remove(Object key, Object value) {
        return removeNode(hash(key), key, value, true, true) != null;
    }

調(diào)用removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable)方法,

    final Node removeNode(int hash, Object key, Object value,
                               boolean matchValue, boolean movable) {
        Node[] tab; Node p; int n, index;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {
            Node node = null, e; K k; V v;
            /*找到待刪除的節(jié)點(diǎn),并用node指向它*/
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;
            else if ((e = p.next) != null) {
                if (p instanceof TreeNode)
                    node = ((TreeNode)p).getTreeNode(hash, key);
                else {
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
            /**/
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
                /*在紅黑樹中刪除該節(jié)點(diǎn)*/
                if (node instanceof TreeNode)
                    ((TreeNode)node).removeTreeNode(this, tab, movable);
                /*該桶只有一個(gè)節(jié)點(diǎn)*/
                else if (node == p)
                    tab[index] = node.next;
                /*在鏈表中刪除該節(jié)點(diǎn)*/
                else
                    p.next = node.next;
                ++modCount;
                --size;
                afterNodeRemoval(node);
                return node;
            }
        }
        return null;
    }
3.5 計(jì)算桶下標(biāo)

在諸如插入或者刪除的操作中都涉及到桶下標(biāo)的計(jì)算

i = (n - 1) & hash    // n-1做hash的掩碼

其中的n表示桶的個(gè)數(shù)(2的整數(shù)次冪),hash由hash(Object key)方法計(jì)算,

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

舉個(gè)例子:

以在一個(gè)容量為16(1000B)的HashMap中,計(jì)算key為字符串"hello"時(shí),應(yīng)該存放的桶下標(biāo)。

第一步,計(jì)算字符串"hello"的hashCode,

"hello".hashCode() = 0000 0101 1110 1001 0001 1000 1101 0010

第二步,在hash(Object key)中,將hashCode的高位(16位)與低位(16位)異或,

   h     = 0000 0101 1110 1001 0001 1000 1101 0010    // hashCode
h >>> 16 = 0000 0000 0000 0000 0000 0101 1110 1001    // hashCode無符號(hào)右移16位
  XOR     = 0000 0101 1110 1001 0001 1101 0011 1011    // 用于計(jì)算桶下標(biāo)的散列值

第三步,將異或的結(jié)果作為計(jì)算桶下標(biāo)的hash值,

hash  = 0000 0101 1110 1001 0001 1101 0011 1011         // 散列值
n - 1 = 0000 0000 0000 0000 0000 0000 0000 1111 (15)    // 桶數(shù)-1
index = 0000 0000 0000 0000 0000 0000 0000 1011 (11)    // 桶下標(biāo)

其中要注意的是,在第三步計(jì)算桶下標(biāo)的時(shí)候,沒有直接使用hash%n這樣取余的方式,因?yàn)槿∮嗟姆绞綇?fù)雜度較位運(yùn)算要高。由于hash算法均勻分布的原則,作為掩碼的二進(jìn)制位全為1,可以使得求得的桶下標(biāo)也是均勻的,因此規(guī)定table的容量應(yīng)該是2的整數(shù)次冪。

而在第二步計(jì)算hash的時(shí)候?qū)ashCode的高位與低位求異或,則是因?yàn)槭褂昧搜诖a的方式求下標(biāo),導(dǎo)致大部分情況下只利用了hash值中低位的信息,容易產(chǎn)生hash沖突,因此將hashCode的高位信息通過這種形式引入到hash值中。

3.6 擴(kuò)容

當(dāng)HashMap中的節(jié)點(diǎn)數(shù)量達(dá)到臨界值時(shí),會(huì)調(diào)用resize()方法對(duì)HashMap進(jìn)行擴(kuò)容,該方法也用于初始化HashMap中的table數(shù)組,

    final Node[] resize() {
        Node[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        /*擴(kuò)容*/
        if (oldCap > 0) {
            /*已經(jīng)達(dá)到最大容量,直接返回*/
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            /*新容量為舊容量的2倍(<<1)*/
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }
        /*使用構(gòu)造函數(shù)中建議的容量*/
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;
        /*默認(rèn)初始化*/
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        /*更新擴(kuò)容閾值*/
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
            Node[] newTab = (Node[])new Node[newCap];    // 構(gòu)造新的table
        table = newTab;
        /*將舊table中的節(jié)點(diǎn)保存到新table*/
        if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    /*桶中只有一個(gè)節(jié)點(diǎn),直接放入新table*/
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    /*桶中是紅黑樹結(jié)構(gòu),拆分放入新table*/
                    else if (e instanceof TreeNode)
                        ((TreeNode)e).split(this, newTab, j, oldCap);
                    /*桶中是鏈表結(jié)構(gòu),放入新table時(shí)保留鏈表中的順序*/
                    else { // preserve order
                        Node loHead = null, loTail = null;
                        Node hiHead = null, hiTail = null;
                        Node next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

在進(jìn)行擴(kuò)容時(shí),首先計(jì)算新table的容量,然后將遍歷舊table中的節(jié)點(diǎn)放到新table中,十分費(fèi)時(shí)。其中涉及對(duì)節(jié)點(diǎn)在新table中的桶下標(biāo)的計(jì)算,HashMap采取一個(gè)機(jī)制,降低重新計(jì)算桶下標(biāo)的復(fù)雜度,

oldTable[index] --> newTable[index+oldCap]

舉個(gè)例子,

假設(shè)原數(shù)組容量oldCap為 16,擴(kuò)容之后newCap為 32:

hash     = 110110    (54)    // 散列值
oldIndex = 000110    (6)     // 舊下標(biāo)
oldCap   = 010000    (16)    // 舊table容量
newCap   = 100000    (32)    // 新table容量

按照求異或的算法,算出新下標(biāo)為

hash     = 110110    (54)    // 散列值
newCap-1 = 011111    (32)    // 新table容量-1
newIndex = 010110    (22)    // 新下標(biāo)

根據(jù)公式算得新的下標(biāo)為

oldIndex + oldCap = 6 + 16 = 22    // 新下標(biāo)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76073.html

相關(guān)文章

  • 金三銀四,2019大廠Android高級(jí)工程師面試題整理

    摘要:原文地址游客前言金三銀四,很多同學(xué)心里大概都準(zhǔn)備著年后找工作或者跳槽。最近有很多同學(xué)都在交流群里求大廠面試題。 最近整理了一波面試題,包括安卓JAVA方面的,目前大廠還是以安卓源碼,算法,以及數(shù)據(jù)結(jié)構(gòu)為主,有一些中小型公司也會(huì)問到混合開發(fā)的知識(shí),至于我為什么傾向于混合開發(fā),我的一句話就是走上編程之路,將來你要學(xué)不僅僅是這些,豐富自己方能與世接軌,做好全棧的裝備。 原文地址:游客kutd...

    tracymac7 評(píng)論0 收藏0
  • [學(xué)習(xí)筆記-Java集合-9] Set - HashSet源碼分析

    摘要:源碼分析屬性內(nèi)部使用虛擬對(duì)象,用來作為放到中構(gòu)造方法非,主要是給使用的構(gòu)造方法都是調(diào)用對(duì)應(yīng)的構(gòu)造方法。遍歷元素直接調(diào)用的的迭代器。什么是機(jī)制是集合中的一種錯(cuò)誤機(jī)制。當(dāng)使用迭代器迭代時(shí),如果發(fā)現(xiàn)集合有修改,則快速失敗做出響應(yīng),拋出異常。 簡(jiǎn)介 集合,這個(gè)概念有點(diǎn)模糊。 廣義上來講,java中的集合是指java.util包下面的容器類,包括和Collection及Map相關(guān)的所有類。 中...

    kohoh_ 評(píng)論0 收藏0
  • Java容器類框架分析(5)HashSet源碼分析

    摘要:到此發(fā)現(xiàn),實(shí)際上可以拆分成跟指的是,則是指實(shí)現(xiàn)了接口,這樣看來,的實(shí)現(xiàn)其實(shí)就比較簡(jiǎn)單了,下面開始分析源碼。 概述 在分析HashSet源碼前,先看看HashSet的繼承關(guān)系 showImg(https://segmentfault.com/img/bVWo4W?w=605&h=425); HashSet繼承關(guān)系從上圖可以看出,HashSet繼承自AbstractSet,實(shí)現(xiàn)了Set接口...

    wslongchen 評(píng)論0 收藏0
  • 后臺(tái)開發(fā)常問面試題集錦(問題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    spacewander 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<