[JavaSE 8 고급 프로 그래 밍 집합 프레임 워 크] 집합 프레임 워 크 입문 시리즈 ③ Map 실현 류 HashMap 20203_2

166751 단어 자바 고급
HashMap · TreeNode 없 음
  • 본체
  • 주석 요점
  • 필기 실현
  • 소스 코드 분석
  • 1. 클래스 서명
  • 2. 관건 적 인 매개 변수 (클래스 변수)
  • 3. 본체 및 속성 (인 스 턴 스 변수)
  • 4. 데이터 구 조 · 일반 노드
  • 5. 도구 정적 클래스 방법
  • ※ 6. 공통 실례 방법
  • 구조 기 * 4
  • 2 삭제 2 개 0 조사 8
  • 1 삭제 1 변경 7 조사 2
  • Cloning and serialization
  • Iterator
  • LinkedHashMap 하위 클래스 지원 방법
  • TreeNode

  • 정의: Hashtable 기반 맵 인터페이스 구현
    Hashtable 과 구별:
  • unsynchronized
  • NULL Key & Value 허용
  • Ht 1.0 HMap 1.2-1.7|1.8

  • 본체
    본질: 본 체 는 Node 유형 배열 - Node[] table 이 고 내부 에 저 장 된 요 소 는 Node 가 트 리 화 조건 에 도달 한 후에 일반 Node 는 TreeNode 로 전환 된다.
    주석 요점
    		1.Iterator           
    		     Iterator  HashMap   “  Capacity”(Bucket    )    (       )(       )2.HashMap           :[16]
    		                              [0.75]
    		      Entry                 ,           ,        *2
    
    		3.(put,get )
    		           Map          ,     rehash   
    
    		4.       
    		rehash     ,         K-V,             Map  
    		    Hash    ,     (  )         Hash         
    
    		5.     sync   
    		                ,                   ,            。
    			Map m = Collections.synchronizedMap(new HashMap(...)); //        
    
    		6.fail-faster
    		      “      ”            ——               
    		     (              )         ,      ConcurrentModificationException
    		  ,              ,      ,              ,            。
    		  ,                  :                 bug。
    
    		                     ;

    필기 실현
    		1.bucket & tree bucket (bin/Treebin)
    		   Hashtable      bucket(    /      )1 bucket          TreeNodes
    		TreeNode   bucket     bucket       ,                
    		      ,  bucket            bucket  ,    bucket      ,      
    
    		2.bucket    
    		    ,   hasCode        ,     ,              Comparable  
    		      compareTo       。             ,       
    		 hashCode()                  hashCode      ,  O(log n)  
    
    		3.TreeNode & NormalNode
    		                  ,    bucket          TreeNode
    		       (         ) ,          。        hashcodes ,       
    
    		     ,     hashCodes, bucket              ,       0.75
    		      0.5,    resizing granularity        。    
    		  bucket     k        (exp(-0.5) pow(0.5, k) / factorial(k))
    			0:    0.60653066
    			1:    0.30326533
    			2:    0.07581633
    			3:    0.01263606
    			4:    0.00157952
    			5:    0.00015795
    			6:    0.00001316
    			7:    0.00000094
    			8:    0.00000006
    		        8          1     [    Hash   ]
    
    		Treebin.root        。  Iterator.remove         ,    TreeNode.root()  
    
    		HashCode      ,                       
    		          “tab”  ,      table,                  
    
    		 bin list/   treeified、split untreeified ,               /    ,
    		            ,       iterator.remove  splits traversals   
    		           ,             (           ),
    		   classes identityHashCodes         
    
    		  vs             LinkedHashMap          。?    
    		           ,             ,        LinkedHashMap           
    		() 
    

    소스 코드 분석
    1. 클래스 서명
    public class HashMap<K,V> 
    	extends AbstractMap<K,V>//implements Map
    	implements Map<K,V>, Cloneable, Serializable
    

    2. 관건 적 인 매개 변수 (클래스 변수)
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;		//      16
    static final int MAXIMUM_CAPACITY = 1 << 30;			//    
    static final float DEFAULT_LOAD_FACTOR = 0.75f;			//      
    static final int TREEIFY_THRESHOLD = 8;					//    
    static final int UNTREEIFY_THRESHOLD = 6;				//    
    static final int MIN_TREEIFY_CAPACITY = 64;				//    ·       64   resize
    //    bin      ,          ,    resizing treeification       
    

    3. 본체 및 속성 (인 스 턴 스 변수)
    //The table
    //          ;    ,      2  。  0          ·tableSizeFor
    transient Node<K,V>[] table;
    
    //Holds cached entrySet()
    //  ,AbstractMap    keySet() values()。
    transient Set<Map.Entry<K,V>> entrySet;
    
    //k-v  
    transient int size;
    
    //       
    //       ,    Map    (rehash)
    transient int modCount;
    
    //     resize     
    //          ,            ,    ,  DEFAULT_INITIAL_CAPACITY
    int threshold;
    
    //    (        )
    final float loadFactor;
    

    4. 데이터 구 조 · 일반 노드
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
    
        Node(int hash, K key, V value, Node<K,V> 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 + "=" + value; }
    
        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }
    
        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
    
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }
    

    5. 도구 정적 클래스 방법
    //    
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
    //     
    //  x   C    Comparable  C,    null
    static Class<?> comparableClassFor(Object x) {
        if (x instanceof Comparable) {
            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
            if ((c = x.getClass()) == String.class) // bypass checks
                return c;
            if ((ts = c.getGenericInterfaces()) != null) {
                for (int i = 0; i < ts.length; ++i) {
                    if (((t = ts[i]) instanceof ParameterizedType) &&
                        ((p = (ParameterizedType)t).getRawType() ==
                         Comparable.class) &&
                        (as = p.getActualTypeArguments()) != null &&
                        as.length == 1 && as[0] == c) // type arg is c
                        return c;
                }
            }
        }
        return null;
    }
    
    //   
    static int compareComparables(Class<?> kc, Object k, Object x) {
        return (x == null || x.getClass() != kc ? 0 :
                ((Comparable)k).compareTo(x));
    }
    
    //        -  -> 2^   [  (64,128)      128]
    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
    

    ※ 6. 공통 실례 방법
       *4, *2, *2, *0, *8
    		  *1, *1, *7, *2	[Java8·Map      ]
    

    구조 기 * 4
    1.        +    
    2.        
    3.      ,       
    4.    Map   HashMap
    
    //1
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);		//new     Table,     threshold
    }
    //2   1  threshold      
    public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); }
    //3
    public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted }
    //4
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);	//false          HashMap LinkedHashMap   
    }
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);			//                
                if (t > threshold)
                    threshold = tableSizeFor(t);				//            
            }
            else if (s > threshold)
                resize();										//  Entry        resize
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);	//for    k-v
            }
        }
    }
    

    첨삭
     *2
    //1.   
    public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)		//  :    tab   HERE
            n = (tab = resize()).length;						//       threshold     
        if ((p = tab[i = (n - 1) & hash]) == null)				//      NULL    1 Node
            tab[i] = newNode(hash, key, value, null);
        else {													//      NULL,      
            Node<K,V> e; K k;
            //IF1       .Key == put.Key      Node p       Node e,    
            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            //IF2             TreeNode.putTreeVal()
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            //ELSE3    
            else {
            	//     
                for (int binCount = 0; ; ++binCount) {
                	//IF1 next      new      
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) 	// -1 for 1st
                            treeifyBin(tab, hash);				//  :   treeifyBin   HERE
                        break;
                    }
                    //IF2       Key       [e = p.next]
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;		//  e=p.next     p,        
                }
            }
            //      Key  Value     V [Put  2]
            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
            resize();
        afterNodeInsertion(evict);	//    LinkedHashMap   
        return null;			//      [Put  1]
    }
    final Node<K,V>[] resize() {					//  |   table        Hash   
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;		
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {		//            
                threshold = Integer.MAX_VALUE;		
                return oldTab;						//   oldTab
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)	// 16   tab  
                newThr = oldThr << 1; 						//          2 
        }
        else if (oldThr > 0) 	//                
            newCap = oldThr;
        else {               	//          DEFAULT_INITIAL_CAPACITY 16 
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        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<K,V>[] newTab = (Node<K,V>[])new Node[newCap];		// new tab   
        table = newTab;			//  tab  
        if (oldTab != null) {	//  ,   hash ,  
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> 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;
    }
    final void treeifyBin(Node<K,V>[] tab, int hash) {				//  
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)	//    
            resize();			//    tab  64	16-32,32-64 2 resize
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            do {
                TreeNode<K,V> p = replacementTreeNode(e, null){
                	return new TreeNode<>(e.hash, e.key, e.value, next);
                };												//    ->   
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);								//     
        }
    }
    Class TreeNode
    final void treeify(Node<K,V>[] tab) {						//   
        TreeNode<K,V> root = null;
        for (TreeNode<K,V> x = this, next; x != null; x = next) {	//         
            next = (TreeNode<K,V>)x.next;
            x.left = x.right = null;
            if (root == null) {									//root     
                x.parent = null;
                x.red = false;
                root = x;
            }
            else {												//    TreeNode
                K k = x.key;
                int h = x.hash;
                Class<?> kc = null;
                for (TreeNode<K,V> p = root;;) {				//  NULL  | 
                    int dir, ph;
                    K pk = p.key;
                    if ((ph = p.hash) > h)
                        dir = -1;
                    else if (ph < h)
                        dir = 1;
                    else if ((kc == null &&
                              (kc = comparableClassFor(k)) == null) ||
                             (dir = compareComparables(kc, k, pk)) == 0)
                        dir = tieBreakOrder(k, pk);		//                      
    
                    TreeNode<K,V> xp = p;
                    if ((p = (dir <= 0) ? p.left : p.right) == null) {
                        x.parent = xp;
                        if (dir <= 0)
                            xp.left = x;
                        else
                            xp.right = x;
                        root = balanceInsertion(root, x);
                        break;
                    }
                }
            }
        }
        moveRootToFront(tab, root);		//    root  bin      
    }
    static int tieBreakOrder(Object a, Object b) {
        int d;
        if (a == null || b == null ||
            (d = a.getClass().getName().
             compareTo(b.getClass().getName())) == 0)
            d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                 -1 : 1);
        return d;
    }
    static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
        int n;
        if (root != null && tab != null && (n = tab.length) > 0) {
            int index = (n - 1) & root.hash;
            TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
            if (root != first) {
                Node<K,V> rn;
                tab[index] = root;
                TreeNode<K,V> rp = root.prev;
                if ((rn = root.next) != null)
                    ((TreeNode<K,V>)rn).prev = rp;
                if (rp != null)
                    rp.next = rn;
                if (first != null)
                    first.prev = root;
                root.next = first;
                root.prev = null;
            }
            assert checkInvariants(root);
        }
    }
    
    //2.   
    // :       Map HashMap       · for putVal       
    public void putAll(Map<? extends K, ? extends V> m) { putMapEntries(m, true); }
    
     *2
    //1.   Key   Value/NULL
    public V remove(Object key) {
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }
    final Node<K,V> removeNode(int hash, Object key, Object value,
                                   boolean matchValue, boolean movable) {
                                   //matchValue  ,         
                                   //movable false,            
        Node<K,V>[] tab; Node<K,V> p; int n, index;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {
            Node<K,V> node = null, e; K k; V v;
            if (p.hash == hash &&	//IF1 hash   && key   || key NULL && K.  equals(Node.key)  
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;			//      Node          node
            else if ((e = p.next) != null) {	//IF2   Node  
                if (p instanceof TreeNode)			//      ,  TreeNode  
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                else {								//     ,       
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;				//     e          node
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
            //        node  
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
                if (node instanceof TreeNode)		//    ,   TreeNode.removeTreeNode
                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                else if (node == p)					//    ,     ? 
                    tab[index] = node.next;
                else 								//    ,    
                    p.next = node.next;				//           .next        .next 
                ++modCount;
                --size;
                afterNodeRemoval(node);				//   LinkedHashMap  
                return node;
            }
        }
        return null;
    }
    
    //2.   
    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;		//  tab[i] NULL
        }
    }
    
     *0
    
     *8
    //1. k-v  
    public int size() { return size; }
    
    //2.  
    public boolean isEmpty() { return size == 0; } 
    
    //3. Key Value NULL
    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        //IF1: table NULL && table.length>0 && hash      Node NULL 
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            //IF2: first       Key hash && first.Key    Key
            	    Key  NULL &&   Key.equals(first.Key)			=>      
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            //IF3: first           NULL      
            if ((e = first.next) != null) {
            	//IF4:          ,   TreeNode getTreeNode      
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                //   ,           
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }
    
    //4.   Key
    public boolean containsKey(Object key) { return getNode(hash(key), key) != null; }
    
    //5.   Value
    public boolean containsValue(Object value) {
        Node<K,V>[] tab; V v;
        if ((tab = table) != null && size > 0) {		// for   
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value ||
                        (value != null && value.equals(v)))
                        return true;
                }
            }
        }
        return false;
    }
    
    //6.  KeySet [HashMap =KeySet+ValueSet || =EntrySet]
    public Set<K> keySet() {			
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new KeySet();			//KeySet     Key,   Iterator()     tab[]
            keySet = ks;
        }
        return ks;
    }
    final class KeySet extends AbstractSet<K> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator<K> iterator()     { return new KeyIterator(); }
        public final boolean contains(Object o) { return containsKey(o); }
        public final boolean remove(Object key) {
            return removeNode(hash(key), key, null, false, true) != null;
        }
        public final Spliterator<K> spliterator() {
            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer<? super K> action) {
            Node<K,V>[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                int mc = modCount;
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
                        action.accept(e.key);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }
    
    //7.  ValueCollection [ KeySet]
    public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new Values();
            values = vs;
        }
        return vs;
    }
    final class Values extends AbstractCollection<V> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator<V> iterator()     { return new ValueIterator(); }
        public final boolean contains(Object o) { return containsValue(o); }
        public final Spliterator<V> spliterator() {
            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer<? super V> action) {
            Node<K,V>[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                int mc = modCount;
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
                        action.accept(e.value);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }
    
    //8.  EntrySet
    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }
    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator<Map.Entry<K,V>> iterator() {
            return new EntryIterator();
        }
        public final boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
            Object key = e.getKey();
            Node<K,V> candidate = getNode(hash(key), key);
            return candidate != null && candidate.equals(e);
        }
        public final boolean remove(Object o) {
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
                Object key = e.getKey();
                Object value = e.getValue();
                return removeNode(hash(key), key, value, true, true) != null;
            }
            return false;
        }
        public final Spliterator<Map.Entry<K,V>> spliterator() {
            return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
            Node<K,V>[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                int mc = modCount;
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
                        action.accept(e);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }
    

    첨삭
    //Java 8 Map  ·    
     1 1 7 2
     *1
    //1.Key   , K-V
    V putIfAbsent(K key, V value)
     *1
    //1.    KV     ,   
    boolean remove(Object key, Object value)
     *7
    //1.    K V,  boolean
    boolean replace(K key, V oldValue, V newValue)
    //2.    K V,  Value|NULL
    V replace(K key, V value)
    //3.   ·  Key V NULL
    V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
    //4.   ·  Key V  
    V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
    //5.   ·K·BiFunction      
    V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
    //6.   ·  Key
    void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
    //7.   ,  value NULL   ,  Key         
    V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
     *2
    //1.       , Key Value
    V getOrDefault(Object key, V defaultValue)
    //2.    
    void forEach(BiConsumer<? super K, ? super V> action)
    

    Cloning and serialization
    public Object clone() loadFactor() capacity() private void writeObject() private void readObject()
    Iterator
    HashIterator HashMapSpliterator KeySpliterator ValueSpliterator EntrySpliterator
    링크 드 HashMap 하위 클래스 지원 방법
    다음 private - package 방법 은 링크 드 HashMap 으로 덮어 쓸 수 있 으 나 다른 하위 클래스 로 덮어 쓰 지 않 습 니 다.LinkedHashMap, view classes, HashSet 에서 newNode () replacementNode () newTreeNode () replacementTreeNode () reitialize () afterNodeAccess () afterNodeInsertion () afterNodeRemoval () internalWriteEntries () 사용 가능
    TreeNode
    22832 chars, 588 line 한 편 씩 주세요.

    좋은 웹페이지 즐겨찾기