Map集合学习

Java中常用的Map实现类主要有:HashMap、HashTable、TreeMap、LinkedHashMap

一:HashMap

HashMap介绍

    HashMap的底层其实是“链表的数组”,即:每个元素其实存放着一个链表,链表存放着哈希值相同的对象们。HashMap是线程不安全的。

   

      1)HashMap不是简单的用key的hashcode()值作为元素的存放下标的,而是通过二次哈希——把key的hashcode()传进HashMap自定义的hash(h)方法中计算位置(有可能大于数组长度了,所以还要对数组长取余),然后通过indexFor(h,len)方法计算出具体的数组下标(用按位与取代取余加快效率),尽量让key尽可能均匀的分配到数组上去,避免造成Hash堆积(某一下标处存放的链表过长)。

         2)HashMap的冲突解决:如果有两个key的hashcode相同,那么经过hash(h)二次哈希后得到的数组索引是一样的,此时就要判断这两个key是否是同一对象:如果两个key的equals方法返回true,则说明两个key是同一对象,则此时把新值覆盖掉旧值;如果equals返回false,则说明是两个不同的key但分配到了同一数组索引位存放,则此时把新增的value添加到该索引位的链表尾。

    3)插入元素时,通过key的hashcode()以及hash算法决定索引,通过equals()决定是插入链表还是覆盖原有值;

              读取元素时,通过key的hashcode()以及hash算法找到索引,通过equals()遍历链表找到相对应的结点值;

            (注:Map存储的是 键值对,不是单指用 key 来索引 value。而是用key 来索引 Entry!Entry就是我们说的 键值对!因此,get()时确定槽位后,在遍历Entry链表时才可以把查找的key与链表结点的key进行比较。)

主要源码:

  1 //新建HashMap,其实是新建了一个数组
  2 public HashMap(int initialCapacity, float loadFactor) {
  3      // initialCapacity代表初始化HashMap的容量,它的最大容量是MAXIMUM_CAPACITY = 1 << 30。
  4         if (initialCapacity < 0)
  5             throw new IllegalArgumentException("Illegal initial capacity: " +
  6                                                initialCapacity);
  7         if (initialCapacity > MAXIMUM_CAPACITY)
  8             initialCapacity = MAXIMUM_CAPACITY;
  9 
 10      // loadFactor代表它的负载因子,默认是是DEFAULT_LOAD_FACTOR=0.75,用来计算threshold临界值的。
 11         if (loadFactor <= 0 || Float.isNaN(loadFactor))
 12             throw new IllegalArgumentException("Illegal load factor: " +
 13                                                loadFactor);
 14 
 15         // Find a power of 2 >= initialCapacity
 16         int capacity = 1;
 17         while (capacity < initialCapacity)
 18             capacity <<= 1;
 19 
 20         this.loadFactor = loadFactor;
 21         threshold = (int)(capacity * loadFactor);
 22         table = new Entry[capacity];//创建数组
 23         init();
 24     }
 25 
 26 //插入元素
 27 public V put(K key, V value) {
 28     // HashMap允许存放null键和null值。
 29     // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。
 30     if (key == null)
 31         return putForNullKey(value);
 32     // 根据key的hashCode重新计算hash值。
 33     int hash = hash(key.hashCode());
 34     // 搜索指定hash值所对应table中的索引。
 35     int i = indexFor(hash, table.length);
 36     // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。
 37     for (Entry<K,V> e = table[i]; e != null; e = e.next) {
 38         Object k;
 39         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
 40             V oldValue = e.value;
 41             e.value = value;
 42             e.recordAccess(this);
 43             return oldValue;
 44         }
 45     }
 46     // 如果i索引处的Entry为null,表明此处还没有Entry。
 47     // modCount记录HashMap中修改结构的次数
 48     modCount++;
 49     // 将key、value添加到i索引处。
 50     addEntry(hash, key, value, i);
 51     return null;
 52 }
 53 void addEntry(int hash, K key, V value, int bucketIndex) {
 54     // 获取指定 bucketIndex 索引处的 Entry 
 55     Entry<K,V> e = table[bucketIndex];
 56     // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry
 57     table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
 58     // 如果 Map 中的 key-value 对的数量超过了极限
 59     if (size++ >= threshold)
 60     // 把 table 对象的长度扩充到原来的2倍。
 61         resize(2 * table.length);
 62 }
 63 
 64 static int hash(int h) {
 65     h ^= (h >>> 20) ^ (h >>> 12);
 66     return h ^ (h >>> 7) ^ (h >>> 4);
 67 }
 68 
 69 static int indexFor(int h, int length) {
 70     return h & (length-1);
 71 }
 72 //它通过 h & (table.length -1) 来得到该对象的保存位,而HashMap底层数组的长度总是 2 的n 次方,这是HashMap在速度上的优化。
 73 //当length总是 2 的n次方时,h& (length-1)运算等价于对length取模,也就是h%length,但是&比%具有更高的效率。
 74 
 75 //读取元素
 76 public V get(Object key) {
 77     if (key == null)
 78         return getForNullKey();
 79     int hash = hash(key.hashCode());
 80     for (Entry<K,V> e = table[indexFor(hash, table.length)];
 81         e != null;
 82         e = e.next) {
 83         Object k;
 84         if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
 85             return e.value;
 86     }
 87     return null;
 88 }
 89 
 90 //HashMap数组扩容
 91           void resize(int newCapacity) {
 92                 Entry[] oldTable = table;
 93                 int oldCapacity = oldTable.length;
 94                 //如果当前的数组长度已经达到最大值,则不在进行调整
 95                 if (oldCapacity == MAXIMUM_CAPACITY) {
 96                     threshold = Integer.MAX_VALUE;
 97                     return;
 98                 }
 99                 //根据传入参数的长度定义新的数组
100                 Entry[] newTable = new Entry[newCapacity];
101                 //按照新的规则,将旧数组中的元素转移到新数组中
102                 transfer(newTable);
103                 table = newTable;
104                 //更新临界值
105                 threshold = (int)(newCapacity * loadFactor);
106             }
107 
108           //旧数组中元素往新数组中迁移
109             void transfer(Entry[] newTable) {
110                 //旧数组
111                 Entry[] src = table;
112                 //新数组长度
113                 int newCapacity = newTable.length;
114                 //遍历旧数组
115                 for (int j = 0; j < src.length; j++) {
116                     Entry<K,V> e = src[j];
117                     if (e != null) {
118                         src[j] = null;
119                         do {
120                             Entry<K,V> next = e.next;
121                             int i = indexFor(e.hash, newCapacity);
122                             e.next = newTable[i];
123                             newTable[i] = e;
124                             e = next;
125                         } while (e != null);
126                     }
127                 }
128             }
View Code

HashMap常用方法

实例介绍:

public static void main(String[] args) {

        HashMap<String, Integer> map=new HashMap<>();
        
       /*Collection<Integer>*///显示所有的value值

        System.out.println(map.values());//[]

        //Hashmap的存值:
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);

        //Hashmap的取值:得到map中key相对应的value的值
        System.out.println(map.get("1"));//null
        System.out.println(map.get("DEMO"));//1
    
        //Hashmap的判断为空:
        System.out.println(map.isEmpty());//false
    
        //判断是否含有key:
        System.out.println(map.containsKey("DEMO"));//true

        //判断是否含有value:
        System.out.println(map.containsValue(1));//true

        //Hashmap的元素个数:
        System.out.println(map.size());//2

        //显示map所有的key:
        System.out.println(map.keySet());//[DEMO1, DEMO2]


        //显示所有的key和value:
        System.out.println(map.entrySet());//[DEMO1=1, DEMO2=2]

        //添加另一个同一类型的map下的所有的key和value:
        HashMap<String, Integer> map1=new HashMap<>();
        map1.putAll(map);
        System.out.println(map1);//{DEMO1=1, DEMO2=2}

        //删除这个key值下的value:
        map.put("DEMO3", 3);
        System.out.println(map.remove("DEMO3"));//3(删除的值)

        //替换这个key的value:(java8)
        map.put("DEMO3", 3);
        System.out.println(map.remove("DEMO3", 1));//false
        System.out.println(map.remove("DEMO2", 3));//true

        //克隆Hashmap:
        System.out.println(map.clone());//{DEMO1=1, DEMO2=2}      
 
        //清空Hashmap:
        map1.clear();//2
        System.out.println(map1);//{}
        
        System.out.println(map.values());//[1, 1]

    }                

HashMap的四种访问方式

第一种:通过Map.entrySet使用iterator遍历key和value,entry放着的就是Map中的某一对key-value;

public void visit_1(HashMap<String,Integer> hm){
        Iterator<Map.Entry<String,Integer>> it = hm.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<String ,Integer> entry = it.next();
            String  key = entry.getKey();
            Integer value = entry.getValue();
        }
    }

第二种:通过Map.keySet()来遍历value,使用foreach读取

public void visit_2(HashMap<String,Integer> hm){
        for (String key:hm.keySet()){
            Integer value = hm.get(key);
        }
    }

第三种:通过Map.Entry遍历key和value(最快,推荐

public void visit_3(HashMap<String,Integer> hm){
        for(Map.Entry<String,Integer> entry:hm.entrySet()){
            String key = entry.getKey();
            Integer value = entry.getValue();
        }
    }

第四种:通过Map.keySet使用iterator遍历key和value,和第二种都是读Key集合,但使用迭代器读取较快

public void visit_4(HashMap<Integer,String> hm){
        long startTime = System.currentTimeMillis();
        Iterator<Integer> it = hm.keySet().iterator();
        while(it.hasNext()){
            Integer key = it.next();
            String value = hm.get(key);
        }
        System.out.println("visit_4 10000000 entry:"
                + (System.currentTimeMillis()-startTime) + " milli seconds");
    }

四种方法比较:

 1 package com.hashmap;
 2 
 3 import java.util.HashMap;
 4 import java.util.Iterator;
 5 import java.util.Map;
 6 
 7 
 8 public class HashMapVisitTest {
 9     public void visit_1(HashMap<Integer,String> hm){
10         long startTime = System.currentTimeMillis();
11         Iterator<Map.Entry<Integer,String>> it = hm.entrySet().iterator();
12         while(it.hasNext()){
13             Map.Entry<Integer,String> entry = it.next();
14             Integer  key = entry.getKey();
15             String value = entry.getValue();
16         }
17         System.out.println("visit_1 10000000 entry:"
18                 + (System.currentTimeMillis()-startTime) + " milli seconds");
19     }
20     public void visit_2(HashMap<Integer,String> hm){
21         long startTime = System.currentTimeMillis();
22         for (Integer key:hm.keySet()){
23             String value = hm.get(key);
24         }
25         System.out.println("visit_1 10000000 entry:"
26                 + (System.currentTimeMillis()-startTime) + " milli seconds");
27     }
28     public void visit_3(HashMap<Integer,String> hm){
29         long startTime = System.currentTimeMillis();
30         for(Map.Entry<Integer,String> entry : hm.entrySet()){
31             Integer key = entry.getKey();
32             String value = entry.getValue();
33         }
34         System.out.println("visit_1 10000000 entry:"
35                 + (System.currentTimeMillis()-startTime) + " milli seconds");
36     }
37     public void visit_4(HashMap<Integer,String> hm){
38         long startTime = System.currentTimeMillis();
39         Iterator<Integer> it = hm.keySet().iterator();
40         while(it.hasNext()){
41             Integer key = it.next();
42             String value = hm.get(key);
43         }
44         System.out.println("visit_1 10000000 entry:"
45                 + (System.currentTimeMillis()-startTime) + " milli seconds");
46     }
47     public static void main(String [] args){
48         HashMap<Integer,String> hm = new HashMap<>();
49         for(int i = 1;i <= 10000000;++i){
50             hm.put(i,"num: " + i);
51         }
52         new HashMapVisitTest().visit_1(hm);
53         new HashMapVisitTest().visit_2(hm);
54         new HashMapVisitTest().visit_3(hm);
55         new HashMapVisitTest().visit_4(hm);
56 
57     }
58 }
View Code

HashMap线程不安全

     HashMap线程不安全的原因从上面的代码可以看出端倪——冲突的解决以及数组扩容  在多线程下容易发生竞态条件(结果取决于执行的顺序)。

     冲突造成不安全:当多个线程共同操作一个HashMap对象时,某一时刻都向map的key拥有相同的hashcode,若key是相同的对象,则最终的value值取决于哪个线程是最终执行的,覆盖掉前面的值;如果key是不同的对象,我们知道此时把值插入链表,而链表当前结点只有一个next指针,那么多个线程中都已缓存了这个指针,都认为这个指针是可用的,并令它指向了当前插入的新结点。那么最后同步回主内存时就会出问题了:指针只有一个。不能同时指向多个结点。

     扩容造成的不安全:当多个线程共同操作一个HashMap对象时,某一时刻同时触发了数组扩容,那么线程轮换执行时都对这个数组进行扩容会覆盖掉前面线程的扩容结果。

二:HashTable

  HashTable底层也是一个“链表数组”,其插入元素和查询元素的策略与HashMap几乎一样。不同的是:很多线程敏感的方法用syncrhoized关键字进行修饰。所以,我们说:HashTable是线程安全的。(类似于Vector对ArrayList线程敏感的方法进行限定)。

主要源码:

  1 package java.util;
  2 import java.io.*;
  3 
  4 public class Hashtable<K,V>
  5     extends Dictionary<K,V>
  6     implements Map<K,V>, Cloneable, java.io.Serializable {
  7 
  8     // Hashtable保存key-value的数组。
  9     // Hashtable是采用拉链法实现的,每一个Entry本质上是一个单向链表
 10     private transient Entry[] table;
 11 
 12     // Hashtable中元素的实际数量
 13     private transient int count;
 14 
 15     // 阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子)
 16     private int threshold;
 17 
 18     // 加载因子
 19     private float loadFactor;
 20 
 21     // Hashtable被改变的次数
 22     private transient int modCount = 0;
 23 
 24     // 序列版本号
 25     private static final long serialVersionUID = 1421746759512286392L;
 26 
 27     // 指定“容量大小”和“加载因子”的构造函数
 28     public Hashtable(int initialCapacity, float loadFactor) {
 29         if (initialCapacity < 0)
 30             throw new IllegalArgumentException("Illegal Capacity: "+
 31                                                initialCapacity);
 32         if (loadFactor <= 0 || Float.isNaN(loadFactor))
 33             throw new IllegalArgumentException("Illegal Load: "+loadFactor);
 34 
 35         if (initialCapacity==0)
 36             initialCapacity = 1;
 37         this.loadFactor = loadFactor;
 38         table = new Entry[initialCapacity];
 39         threshold = (int)(initialCapacity * loadFactor);
 40     }
 41 
 42     // 指定“容量大小”的构造函数
 43     public Hashtable(int initialCapacity) {
 44         this(initialCapacity, 0.75f);
 45     }
 46 
 47     // 默认构造函数。
 48     public Hashtable() {
 49         // 默认构造函数,指定的容量大小是11;加载因子是0.75
 50         this(11, 0.75f);
 51     }
 52 
 53     // 包含“子Map”的构造函数
 54     public Hashtable(Map<? extends K, ? extends V> t) {
 55         this(Math.max(2*t.size(), 11), 0.75f);
 56         // 将“子Map”的全部元素都添加到Hashtable中
 57         putAll(t);
 58     }
 59 
 60     public synchronized int size() {
 61         return count;
 62     }
 63 
 64     public synchronized boolean isEmpty() {
 65         return count == 0;
 66     }
 67 
 68     // 返回“所有key”的枚举对象
 69     public synchronized Enumeration<K> keys() {
 70         return this.<K>getEnumeration(KEYS);
 71     }
 72 
 73     // 返回“所有value”的枚举对象
 74     public synchronized Enumeration<V> elements() {
 75         return this.<V>getEnumeration(VALUES);
 76     }
 77 
 78     // 判断Hashtable是否包含“值(value)”
 79     public synchronized boolean contains(Object value) {
 80         // Hashtable中“键值对”的value不能是null,
 81         // 若是null的话,抛出异常!
 82         if (value == null) {
 83             throw new NullPointerException();
 84         }
 85 
 86         // 从后向前遍历table数组中的元素(Entry)
 87         // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value
 88         Entry tab[] = table;
 89         for (int i = tab.length ; i-- > 0 ;) {
 90             for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
 91                 if (e.value.equals(value)) {
 92                     return true;
 93                 }
 94             }
 95         }
 96         return false;
 97     }
 98 
 99     public boolean containsValue(Object value) {
100         return contains(value);
101     }
102 
103     // 判断Hashtable是否包含key
104     public synchronized boolean containsKey(Object key) {
105         Entry tab[] = table;
106         int hash = key.hashCode();
107         // 计算索引值,
108         // % tab.length 的目的是防止数据越界
109         int index = (hash & 0x7FFFFFFF) % tab.length;
110         // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
111         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
112             if ((e.hash == hash) && e.key.equals(key)) {
113                 return true;
114             }
115         }
116         return false;
117     }
118 
119     // 返回key对应的value,没有的话返回null
120     public synchronized V get(Object key) {
121         Entry tab[] = table;
122         int hash = key.hashCode();
123         // 计算索引值,
124         int index = (hash & 0x7FFFFFFF) % tab.length;
125         // 找到“key对应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
126         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
127             if ((e.hash == hash) && e.key.equals(key)) {
128                 return e.value;
129             }
130         }
131         return null;
132     }
133 
134     // 调整Hashtable的长度,将长度变成原来的(2倍+1)
135     // (01) 将“旧的Entry数组”赋值给一个临时变量。
136     // (02) 创建一个“新的Entry数组”,并赋值给“旧的Entry数组”
137     // (03) 将“Hashtable”中的全部元素依次添加到“新的Entry数组”中
138     protected void rehash() {
139         int oldCapacity = table.length;
140         Entry[] oldMap = table;
141 
142         int newCapacity = oldCapacity * 2 + 1;
143         Entry[] newMap = new Entry[newCapacity];
144 
145         modCount++;
146         threshold = (int)(newCapacity * loadFactor);
147         table = newMap;
148 
149         for (int i = oldCapacity ; i-- > 0 ;) {
150             for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
151                 Entry<K,V> e = old;
152                 old = old.next;
153 
154                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
155                 e.next = newMap[index];
156                 newMap[index] = e;
157             }
158         }
159     }
160 
161     // 将“key-value”添加到Hashtable中
162     public synchronized V put(K key, V value) {
163         // Hashtable中不能插入value为null的元素!!!
164         if (value == null) {
165             throw new NullPointerException();
166         }
167 
168         // 若“Hashtable中已存在键为key的键值对”,
169         // 则用“新的value”替换“旧的value”
170         Entry tab[] = table;
171         int hash = key.hashCode();
172         int index = (hash & 0x7FFFFFFF) % tab.length;
173         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
174             if ((e.hash == hash) && e.key.equals(key)) {
175                 V old = e.value;
176                 e.value = value;
177                 return old;
178                 }
179         }
180 
181         // 若“Hashtable中不存在键为key的键值对”,
182         // (01) 将“修改统计数”+1
183         modCount++;
184         // (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)
185         //  则调整Hashtable的大小
186         if (count >= threshold) {
187             // Rehash the table if the threshold is exceeded
188             rehash();
189 
190             tab = table;
191             index = (hash & 0x7FFFFFFF) % tab.length;
192         }
193 
194         // (03) 将“Hashtable中index”位置的Entry(链表)保存到e中
195         Entry<K,V> e = tab[index];
196         // (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。        
197         tab[index] = new Entry<K,V>(hash, key, value, e);
198         // (05) 将“Hashtable的实际容量”+1
199         count++;
200         return null;
201     }
202 
203     // 删除Hashtable中键为key的元素
204     public synchronized V remove(Object key) {
205         Entry tab[] = table;
206         int hash = key.hashCode();
207         int index = (hash & 0x7FFFFFFF) % tab.length;
208         // 找到“key对应的Entry(链表)”
209         // 然后在链表中找出要删除的节点,并删除该节点。
210         for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
211             if ((e.hash == hash) && e.key.equals(key)) {
212                 modCount++;
213                 if (prev != null) {
214                     prev.next = e.next;
215                 } else {
216                     tab[index] = e.next;
217                 }
218                 count--;
219                 V oldValue = e.value;
220                 e.value = null;
221                 return oldValue;
222             }
223         }
224         return null;
225     }
226 
227     // 将“Map(t)”的中全部元素逐一添加到Hashtable中
228     public synchronized void putAll(Map<? extends K, ? extends V> t) {
229         for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
230             put(e.getKey(), e.getValue());
231     }
232 
233     // 清空Hashtable
234     // 将Hashtable的table数组的值全部设为null
235     public synchronized void clear() {
236         Entry tab[] = table;
237         modCount++;
238         for (int index = tab.length; --index >= 0; )
239             tab[index] = null;
240         count = 0;
241     }
242 
243     // 克隆一个Hashtable,并以Object的形式返回。
244     public synchronized Object clone() {
245         try {
246             Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
247             t.table = new Entry[table.length];
248             for (int i = table.length ; i-- > 0 ; ) {
249                 t.table[i] = (table[i] != null)
250                 ? (Entry<K,V>) table[i].clone() : null;
251             }
252             t.keySet = null;
253             t.entrySet = null;
254             t.values = null;
255             t.modCount = 0;
256             return t;
257         } catch (CloneNotSupportedException e) {
258             // this shouldn't happen, since we are Cloneable
259             throw new InternalError();
260         }
261     }
262 
263     public synchronized String toString() {
264         int max = size() - 1;
265         if (max == -1)
266             return "{}";
267 
268         StringBuilder sb = new StringBuilder();
269         Iterator<Map.Entry<K,V>> it = entrySet().iterator();
270 
271         sb.append('{');
272         for (int i = 0; ; i++) {
273             Map.Entry<K,V> e = it.next();
274             K key = e.getKey();
275             V value = e.getValue();
276             sb.append(key   == this ? "(this Map)" : key.toString());
277             sb.append('=');
278             sb.append(value == this ? "(this Map)" : value.toString());
279 
280             if (i == max)
281                 return sb.append('}').toString();
282             sb.append(", ");
283         }
284     }
285 
286     // 获取Hashtable的枚举类对象
287     // 若Hashtable的实际大小为0,则返回“空枚举类”对象;
288     // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
289     private <T> Enumeration<T> getEnumeration(int type) {
290     if (count == 0) {
291         return (Enumeration<T>)emptyEnumerator;
292     } else {
293         return new Enumerator<T>(type, false);
294     }
295     }
296 
297     // 获取Hashtable的迭代器
298     // 若Hashtable的实际大小为0,则返回“空迭代器”对象;
299     // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
300     private <T> Iterator<T> getIterator(int type) {
301         if (count == 0) {
302             return (Iterator<T>) emptyIterator;
303         } else {
304             return new Enumerator<T>(type, true);
305         }
306     }
307 
308     // Hashtable的“key的集合”。它是一个Set,意味着没有重复元素
309     private transient volatile Set<K> keySet = null;
310     // Hashtable的“key-value的集合”。它是一个Set,意味着没有重复元素
311     private transient volatile Set<Map.Entry<K,V>> entrySet = null;
312     // Hashtable的“key-value的集合”。它是一个Collection,意味着可以有重复元素
313     private transient volatile Collection<V> values = null;
314 
315     // 返回一个被synchronizedSet封装后的KeySet对象
316     // synchronizedSet封装的目的是对KeySet的所有方法都添加synchronized,实现多线程同步
317     public Set<K> keySet() {
318         if (keySet == null)
319             keySet = Collections.synchronizedSet(new KeySet(), this);
320         return keySet;
321     }
322 
323     // Hashtable的Key的Set集合。
324     // KeySet继承于AbstractSet,所以,KeySet中的元素没有重复的。
325     private class KeySet extends AbstractSet<K> {
326         public Iterator<K> iterator() {
327             return getIterator(KEYS);
328         }
329         public int size() {
330             return count;
331         }
332         public boolean contains(Object o) {
333             return containsKey(o);
334         }
335         public boolean remove(Object o) {
336             return Hashtable.this.remove(o) != null;
337         }
338         public void clear() {
339             Hashtable.this.clear();
340         }
341     }
342 
343     // 返回一个被synchronizedSet封装后的EntrySet对象
344     // synchronizedSet封装的目的是对EntrySet的所有方法都添加synchronized,实现多线程同步
345     public Set<Map.Entry<K,V>> entrySet() {
346         if (entrySet==null)
347             entrySet = Collections.synchronizedSet(new EntrySet(), this);
348         return entrySet;
349     }
350 
351     // Hashtable的Entry的Set集合。
352     // EntrySet继承于AbstractSet,所以,EntrySet中的元素没有重复的。
353     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
354         public Iterator<Map.Entry<K,V>> iterator() {
355             return getIterator(ENTRIES);
356         }
357 
358         public boolean add(Map.Entry<K,V> o) {
359             return super.add(o);
360         }
361 
362         // 查找EntrySet中是否包含Object(0)
363         // 首先,在table中找到o对应的Entry(Entry是一个单向链表)
364         // 然后,查找Entry链表中是否存在Object
365         public boolean contains(Object o) {
366             if (!(o instanceof Map.Entry))
367                 return false;
368             Map.Entry entry = (Map.Entry)o;
369             Object key = entry.getKey();
370             Entry[] tab = table;
371             int hash = key.hashCode();
372             int index = (hash & 0x7FFFFFFF) % tab.length;
373 
374             for (Entry e = tab[index]; e != null; e = e.next)
375                 if (e.hash==hash && e.equals(entry))
376                     return true;
377             return false;
378         }
379 
380         // 删除元素Object(0)
381         // 首先,在table中找到o对应的Entry(Entry是一个单向链表)
382         // 然后,删除链表中的元素Object
383         public boolean remove(Object o) {
384             if (!(o instanceof Map.Entry))
385                 return false;
386             Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
387             K key = entry.getKey();
388             Entry[] tab = table;
389             int hash = key.hashCode();
390             int index = (hash & 0x7FFFFFFF) % tab.length;
391 
392             for (Entry<K,V> e = tab[index], prev = null; e != null;
393                  prev = e, e = e.next) {
394                 if (e.hash==hash && e.equals(entry)) {
395                     modCount++;
396                     if (prev != null)
397                         prev.next = e.next;
398                     else
399                         tab[index] = e.next;
400 
401                     count--;
402                     e.value = null;
403                     return true;
404                 }
405             }
406             return false;
407         }
408 
409         public int size() {
410             return count;
411         }
412 
413         public void clear() {
414             Hashtable.this.clear();
415         }
416     }
417 
418     // 返回一个被synchronizedCollection封装后的ValueCollection对象
419     // synchronizedCollection封装的目的是对ValueCollection的所有方法都添加synchronized,实现多线程同步
420     public Collection<V> values() {
421     if (values==null)
422         values = Collections.synchronizedCollection(new ValueCollection(),
423                                                         this);
424         return values;
425     }
426 
427     // Hashtable的value的Collection集合。
428     // ValueCollection继承于AbstractCollection,所以,ValueCollection中的元素可以重复的。
429     private class ValueCollection extends AbstractCollection<V> {
430         public Iterator<V> iterator() {
431         return getIterator(VALUES);
432         }
433         public int size() {
434             return count;
435         }
436         public boolean contains(Object o) {
437             return containsValue(o);
438         }
439         public void clear() {
440             Hashtable.this.clear();
441         }
442     }
443 
444     // 重新equals()函数
445     // 若两个Hashtable的所有key-value键值对都相等,则判断它们两个相等
446     public synchronized boolean equals(Object o) {
447         if (o == this)
448             return true;
449 
450         if (!(o instanceof Map))
451             return false;
452         Map<K,V> t = (Map<K,V>) o;
453         if (t.size() != size())
454             return false;
455 
456         try {
457             // 通过迭代器依次取出当前Hashtable的key-value键值对
458             // 并判断该键值对,存在于Hashtable(o)中。
459             // 若不存在,则立即返回false;否则,遍历完“当前Hashtable”并返回true。
460             Iterator<Map.Entry<K,V>> i = entrySet().iterator();
461             while (i.hasNext()) {
462                 Map.Entry<K,V> e = i.next();
463                 K key = e.getKey();
464                 V value = e.getValue();
465                 if (value == null) {
466                     if (!(t.get(key)==null && t.containsKey(key)))
467                         return false;
468                 } else {
469                     if (!value.equals(t.get(key)))
470                         return false;
471                 }
472             }
473         } catch (ClassCastException unused)   {
474             return false;
475         } catch (NullPointerException unused) {
476             return false;
477         }
478 
479         return true;
480     }
481 
482     // 计算Hashtable的哈希值
483     // 若 Hashtable的实际大小为0 或者 加载因子<0,则返回0。
484     // 否则,返回“Hashtable中的每个Entry的key和value的异或值 的总和”。
485     public synchronized int hashCode() {
486         int h = 0;
487         if (count == 0 || loadFactor < 0)
488             return h;  // Returns zero
489 
490         loadFactor = -loadFactor;  // Mark hashCode computation in progress
491         Entry[] tab = table;
492         for (int i = 0; i < tab.length; i++)
493             for (Entry e = tab[i]; e != null; e = e.next)
494                 h += e.key.hashCode() ^ e.value.hashCode();
495         loadFactor = -loadFactor;  // Mark hashCode computation complete
496 
497         return h;
498     }
499 
500     // java.io.Serializable的写入函数
501     // 将Hashtable的“总的容量,实际容量,所有的Entry”都写入到输出流中
502     private synchronized void writeObject(java.io.ObjectOutputStream s)
503         throws IOException
504     {
505         // Write out the length, threshold, loadfactor
506         s.defaultWriteObject();
507 
508         // Write out length, count of elements and then the key/value objects
509         s.writeInt(table.length);
510         s.writeInt(count);
511         for (int index = table.length-1; index >= 0; index--) {
512             Entry entry = table[index];
513 
514             while (entry != null) {
515             s.writeObject(entry.key);
516             s.writeObject(entry.value);
517             entry = entry.next;
518             }
519         }
520     }
521 
522     // java.io.Serializable的读取函数:根据写入方式读出
523     // 将Hashtable的“总的容量,实际容量,所有的Entry”依次读出
524     private void readObject(java.io.ObjectInputStream s)
525          throws IOException, ClassNotFoundException
526     {
527         // Read in the length, threshold, and loadfactor
528         s.defaultReadObject();
529 
530         // Read the original length of the array and number of elements
531         int origlength = s.readInt();
532         int elements = s.readInt();
533 
534         // Compute new size with a bit of room 5% to grow but
535         // no larger than the original size.  Make the length
536         // odd if it's large enough, this helps distribute the entries.
537         // Guard against the length ending up zero, that's not valid.
538         int length = (int)(elements * loadFactor) + (elements / 20) + 3;
539         if (length > elements && (length & 1) == 0)
540             length--;
541         if (origlength > 0 && length > origlength)
542             length = origlength;
543 
544         Entry[] table = new Entry[length];
545         count = 0;
546 
547         // Read the number of elements and then all the key/value objects
548         for (; elements > 0; elements--) {
549             K key = (K)s.readObject();
550             V value = (V)s.readObject();
551                 // synch could be eliminated for performance
552                 reconstitutionPut(table, key, value);
553         }
554         this.table = table;
555     }
556 
557     private void reconstitutionPut(Entry[] tab, K key, V value)
558         throws StreamCorruptedException
559     {
560         if (value == null) {
561             throw new java.io.StreamCorruptedException();
562         }
563         // Makes sure the key is not already in the hashtable.
564         // This should not happen in deserialized version.
565         int hash = key.hashCode();
566         int index = (hash & 0x7FFFFFFF) % tab.length;
567         for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
568             if ((e.hash == hash) && e.key.equals(key)) {
569                 throw new java.io.StreamCorruptedException();
570             }
571         }
572         // Creates the new entry.
573         Entry<K,V> e = tab[index];
574         tab[index] = new Entry<K,V>(hash, key, value, e);
575         count++;
576     }
577 
578     // Hashtable的Entry节点,它本质上是一个单向链表。
579     // 也因此,我们才能推断出Hashtable是由拉链法实现的散列表
580     private static class Entry<K,V> implements Map.Entry<K,V> {
581         // 哈希值
582         int hash;
583         K key;
584         V value;
585         // 指向的下一个Entry,即链表的下一个节点
586         Entry<K,V> next;
587 
588         // 构造函数
589         protected Entry(int hash, K key, V value, Entry<K,V> next) {
590             this.hash = hash;
591             this.key = key;
592             this.value = value;
593             this.next = next;
594         }
595 
596         protected Object clone() {
597             return new Entry<K,V>(hash, key, value,
598                   (next==null ? null : (Entry<K,V>) next.clone()));
599         }
600 
601         public K getKey() {
602             return key;
603         }
604 
605         public V getValue() {
606             return value;
607         }
608 
609         // 设置value。若value是null,则抛出异常。
610         public V setValue(V value) {
611             if (value == null)
612                 throw new NullPointerException();
613 
614             V oldValue = this.value;
615             this.value = value;
616             return oldValue;
617         }
618 
619         // 覆盖equals()方法,判断两个Entry是否相等。
620         // 若两个Entry的key和value都相等,则认为它们相等。
621         public boolean equals(Object o) {
622             if (!(o instanceof Map.Entry))
623                 return false;
624             Map.Entry e = (Map.Entry)o;
625 
626             return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
627                (value==null ? e.getValue()==null : value.equals(e.getValue()));
628         }
629 
630         public int hashCode() {
631             return hash ^ (value==null ? 0 : value.hashCode());
632         }
633 
634         public String toString() {
635             return key.toString()+"="+value.toString();
636         }
637     }
638 
639     private static final int KEYS = 0;
640     private static final int VALUES = 1;
641     private static final int ENTRIES = 2;
642 
643     // Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。因为,它同时实现了 “Enumerator接口”和“Iterator接口”。
644     private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
645         // 指向Hashtable的table
646         Entry[] table = Hashtable.this.table;
647         // Hashtable的总的大小
648         int index = table.length;
649         Entry<K,V> entry = null;
650         Entry<K,V> lastReturned = null;
651         int type;
652 
653         // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
654         // iterator为true,表示它是迭代器;否则,是枚举类。
655         boolean iterator;
656 
657         // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
658         protected int expectedModCount = modCount;
659 
660         Enumerator(int type, boolean iterator) {
661             this.type = type;
662             this.iterator = iterator;
663         }
664 
665         // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
666         public boolean hasMoreElements() {
667             Entry<K,V> e = entry;
668             int i = index;
669             Entry[] t = table;
670             /* Use locals for faster loop iteration */
671             while (e == null && i > 0) {
672                 e = t[--i];
673             }
674             entry = e;
675             index = i;
676             return e != null;
677         }
678 
679         // 获取下一个元素
680         // 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”
681         // 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
682         // 然后,依次向后遍历单向链表Entry。
683         public T nextElement() {
684             Entry<K,V> et = entry;
685             int i = index;
686             Entry[] t = table;
687             /* Use locals for faster loop iteration */
688             while (et == null && i > 0) {
689                 et = t[--i];
690             }
691             entry = et;
692             index = i;
693             if (et != null) {
694                 Entry<K,V> e = lastReturned = entry;
695                 entry = e.next;
696                 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
697             }
698             throw new NoSuchElementException("Hashtable Enumerator");
699         }
700 
701         // 迭代器Iterator的判断是否存在下一个元素
702         // 实际上,它是调用的hasMoreElements()
703         public boolean hasNext() {
704             return hasMoreElements();
705         }
706 
707         // 迭代器获取下一个元素
708         // 实际上,它是调用的nextElement()
709         public T next() {
710             if (modCount != expectedModCount)
711                 throw new ConcurrentModificationException();
712             return nextElement();
713         }
714 
715         // 迭代器的remove()接口。
716         // 首先,它在table数组中找出要删除元素所在的Entry,
717         // 然后,删除单向链表Entry中的元素。
718         public void remove() {
719             if (!iterator)
720                 throw new UnsupportedOperationException();
721             if (lastReturned == null)
722                 throw new IllegalStateException("Hashtable Enumerator");
723             if (modCount != expectedModCount)
724                 throw new ConcurrentModificationException();
725 
726             synchronized(Hashtable.this) {
727                 Entry[] tab = Hashtable.this.table;
728                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
729 
730                 for (Entry<K,V> e = tab[index], prev = null; e != null;
731                      prev = e, e = e.next) {
732                     if (e == lastReturned) {
733                         modCount++;
734                         expectedModCount++;
735                         if (prev == null)
736                             tab[index] = e.next;
737                         else
738                             prev.next = e.next;
739                         count--;
740                         lastReturned = null;
741                         return;
742                     }
743                 }
744                 throw new ConcurrentModificationException();
745             }
746         }
747     }
748 
749 
750     private static Enumeration emptyEnumerator = new EmptyEnumerator();
751     private static Iterator emptyIterator = new EmptyIterator();
752 
753     // 空枚举类
754     // 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
755     private static class EmptyEnumerator implements Enumeration<Object> {
756 
757         EmptyEnumerator() {
758         }
759 
760         // 空枚举类的hasMoreElements() 始终返回false
761         public boolean hasMoreElements() {
762             return false;
763         }
764 
765         // 空枚举类的nextElement() 抛出异常
766         public Object nextElement() {
767             throw new NoSuchElementException("Hashtable Enumerator");
768         }
769     }
770 
771 
772     // 空迭代器
773     // 当Hashtable的实际大小为0;此时,又要通过迭代器遍历Hashtable时,返回的是“空迭代器”的对象。
774     private static class EmptyIterator implements Iterator<Object> {
775 
776         EmptyIterator() {
777         }
778 
779         public boolean hasNext() {
780             return false;
781         }
782 
783         public Object next() {
784             throw new NoSuchElementException("Hashtable Iterator");
785         }
786 
787         public void remove() {
788             throw new IllegalStateException("Hashtable Iterator");
789         }
790 
791     }
792 }
View Code

三:TreeMap

     与前面的两个map实现类不同,TreeMap是通过红黑树来实现的。所以针对TreeMap的插入元素、查找元素、删除元素等都是对红黑树的操作。

主要源码:

  1  //1:插入元素
  2 //两步:一是插入到排序二叉树的合适位置,二是对二叉树进行平衡(左右旋、重新着色)
  3 
  4 public V put(K key, V value) {  
  5                //用t表示二叉树的当前节点  
  6                 Entry<K,V> t = root;  
  7                 //t为null表示一个空树,即TreeMap中没有任何元素,直接插入  
  8                 if (t == null) {  
  9                     //比较key值,个人觉得这句代码没有任何意义,空树还需要比较、排序?  
 10                     compare(key, key); // type (and possibly null) check  
 11                     //将新的key-value键值对创建为一个Entry节点,并将该节点赋予给root  
 12                     root = new Entry<>(key, value, null);  
 13                     //容器的size = 1,表示TreeMap集合中存在一个元素  
 14                     size = 1;  
 15                     //修改次数 + 1  
 16                     modCount++;  
 17                     return null;  
 18                 }  
 19                 int cmp;     //cmp表示key排序的返回结果  
 20                 Entry<K,V> parent;   //父节点  
 21                 // split comparator and comparable paths  
 22                 Comparator<? super K> cpr = comparator;    //指定的排序算法  
 23                 //如果cpr不为空,则采用既定的排序算法进行创建TreeMap集合  
 24                 if (cpr != null) {  
 25                     do {  
 26                         parent = t;      //parent指向上次循环后的t  
 27                         //比较新增节点的key和当前节点key的大小  
 28                         cmp = cpr.compare(key, t.key);  
 29                         //cmp返回值小于0,表示新增节点的key小于当前节点的key,则以当前节点的左子节点作为新的当前节点  
 30                         if (cmp < 0)  
 31                             t = t.left;  
 32                         //cmp返回值大于0,表示新增节点的key大于当前节点的key,则以当前节点的右子节点作为新的当前节点  
 33                         else if (cmp > 0)  
 34                             t = t.right;  
 35                         //cmp返回值等于0,表示两个key值相等,则新值覆盖旧值,并返回新值  
 36                         else  
 37                             return t.setValue(value);  
 38                     } while (t != null);  
 39                 }  
 40                 //如果cpr为空,则采用默认的排序算法进行创建TreeMap集合  
 41                 else {  
 42                     if (key == null)     //key值为空抛出异常  
 43                         throw new NullPointerException();  
 44                     /* 下面处理过程和上面一样 */  
 45                     Comparable<? super K> k = (Comparable<? super K>) key;  
 46                     do {  
 47                         parent = t;  
 48                         cmp = k.compareTo(t.key);  
 49                         if (cmp < 0)  
 50                             t = t.left;  
 51                         else if (cmp > 0)  
 52                             t = t.right;  
 53                         else  
 54                             return t.setValue(value);  
 55                     } while (t != null);  
 56                 }  
 57                 //将新增节点当做parent的子节点  
 58                 Entry<K,V> e = new Entry<>(key, value, parent);  
 59                 //如果新增节点的key小于parent的key,则当做左子节点  
 60                 if (cmp < 0)  
 61                     parent.left = e;  
 62               //如果新增节点的key大于parent的key,则当做右子节点  
 63                 else  
 64                     parent.right = e;  
 65                 /*  
 66                  *  上面已经完成了排序二叉树的的构建,将新增节点插入该树中的合适位置  
 67                  *  下面fixAfterInsertion()方法就是对这棵树进行调整、平衡,具体过程参考上面的五种情况  
 68                  */  
 69                 fixAfterInsertion(e);  
 70                 //TreeMap元素数量 + 1  
 71                 size++;  
 72                 //TreeMap容器修改次数 + 1  
 73                 modCount++;  
 74                 return null;  
 75             }  
 76     /** 
 77          * 新增节点后的修复操作 
 78          * x 表示新增节点 
 79          */  
 80          private void fixAfterInsertion(Entry<K,V> x) {  
 81                 x.color = RED;    //新增节点的颜色为红色  
 82       
 83                 //循环 直到 x不是根节点,且x的父节点不为红色  
 84                 while (x != null && x != root && x.parent.color == RED) {  
 85                     //如果X的父节点(P)是其父节点的父节点(G)的左节点  
 86                     if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {  
 87                         //获取X的叔节点(U)  
 88                         Entry<K,V> y = rightOf(parentOf(parentOf(x)));  
 89                         //如果X的叔节点(U) 为红色(情况三)  
 90                         if (colorOf(y) == RED) {       
 91                             //将X的父节点(P)设置为黑色  
 92                             setColor(parentOf(x), BLACK);  
 93                             //将X的叔节点(U)设置为黑色  
 94                             setColor(y, BLACK);  
 95                             //将X的父节点的父节点(G)设置红色  
 96                             setColor(parentOf(parentOf(x)), RED);  
 97                             x = parentOf(parentOf(x));  
 98                         }  
 99                         //如果X的叔节点(U为黑色);这里会存在两种情况(情况四、情况五)  
100                         else {     
101                             //如果X节点为其父节点(P)的右子树,则进行左旋转(情况四)  
102                             if (x == rightOf(parentOf(x))) {  
103                                 //将X的父节点作为X  
104                                 x = parentOf(x);  
105                                 //右旋转  
106                                 rotateLeft(x);  
107                             }  
108                             //(情况五)  
109                             //将X的父节点(P)设置为黑色  
110                             setColor(parentOf(x), BLACK);  
111                             //将X的父节点的父节点(G)设置红色  
112                             setColor(parentOf(parentOf(x)), RED);  
113                             //以X的父节点的父节点(G)为中心右旋转  
114                             rotateRight(parentOf(parentOf(x)));  
115                         }  
116                     }  
117                     //如果X的父节点(P)是其父节点的父节点(G)的右节点  
118                     else {  
119                         //获取X的叔节点(U)  
120                         Entry<K,V> y = leftOf(parentOf(parentOf(x)));  
121                       //如果X的叔节点(U) 为红色(情况三)  
122                         if (colorOf(y) == RED) {  
123                             //将X的父节点(P)设置为黑色  
124                             setColor(parentOf(x), BLACK);  
125                             //将X的叔节点(U)设置为黑色  
126                             setColor(y, BLACK);  
127                             //将X的父节点的父节点(G)设置红色  
128                             setColor(parentOf(parentOf(x)), RED);  
129                             x = parentOf(parentOf(x));  
130                         }  
131                       //如果X的叔节点(U为黑色);这里会存在两种情况(情况四、情况五)  
132                         else {  
133                             //如果X节点为其父节点(P)的右子树,则进行左旋转(情况四)  
134                             if (x == leftOf(parentOf(x))) {  
135                                 //将X的父节点作为X  
136                                 x = parentOf(x);  
137                                //右旋转  
138                                 rotateRight(x);  
139                             }  
140                             //(情况五)  
141                             //将X的父节点(P)设置为黑色  
142                             setColor(parentOf(x), BLACK);  
143                             //将X的父节点的父节点(G)设置红色  
144                             setColor(parentOf(parentOf(x)), RED);  
145                             //以X的父节点的父节点(G)为中心右旋转  
146                             rotateLeft(parentOf(parentOf(x)));  
147                         }  
148                     }  
149                 }  
150                 //将根节点G强制设置为黑色  
151                 root.color = BLACK;  
152             }  
153     private void rotateLeft(Entry<K,V> p) {  
154             if (p != null) {  
155                 //获取P的右子节点,其实这里就相当于新增节点N(情况四而言)  
156                 Entry<K,V> r = p.right;  
157                 //将R的左子树设置为P的右子树  
158                 p.right = r.left;  
159                 //若R的左子树不为空,则将P设置为R左子树的父亲  
160                 if (r.left != null)  
161                     r.left.parent = p;  
162                 //将P的父亲设置R的父亲  
163                 r.parent = p.parent;  
164                 //如果P的父亲为空,则将R设置为跟节点  
165                 if (p.parent == null)  
166                     root = r;  
167                 //如果P为其父节点(G)的左子树,则将R设置为P父节点(G)左子树  
168                 else if (p.parent.left == p)  
169                     p.parent.left = r;  
170                 //否则R设置为P的父节点(G)的右子树  
171                 else  
172                     p.parent.right = r;  
173                 //将P设置为R的左子树  
174                 r.left = p;  
175                 //将R设置为P的父节点  
176                 p.parent = r;  
177             }  
178         }  
179     private void rotateRight(Entry<K,V> p) {  
180             if (p != null) {  
181                 //将L设置为P的左子树  
182                 Entry<K,V> l = p.left;  
183                 //将L的右子树设置为P的左子树  
184                 p.left = l.right;  
185                 //若L的右子树不为空,则将P设置L的右子树的父节点  
186                 if (l.right != null)   
187                     l.right.parent = p;  
188                 //将P的父节点设置为L的父节点  
189                 l.parent = p.parent;  
190                 //如果P的父节点为空,则将L设置根节点  
191                 if (p.parent == null)  
192                     root = l;  
193                 //若P为其父节点的右子树,则将L设置为P的父节点的右子树  
194                 else if (p.parent.right == p)  
195                     p.parent.right = l;  
196                 //否则将L设置为P的父节点的左子树  
197                 else   
198                     p.parent.left = l;  
199                 //将P设置为L的右子树  
200                 l.right = p;  
201                 //将L设置为P的父节点  
202                 p.parent = l;  
203             }  
204         }
205 
206 //2:删除元素
207 //在红黑树中删除一个结点。红黑树删除结点D:取D右分支最左边,或者左分支最右边的//子结点取代D,然后把子节点删除,之后再对红黑树进行平衡。
208 
209 private void deleteEntry(Entry<K,V> p) {  
210             modCount++;      //修改次数 +1  
211             size--;          //元素个数 -1  
212       
213             /* 
214              * 被删除节点的左子树和右子树都不为空,那么就用 p节点的中序后继节点代替 p 节点 
215              * successor(P)方法为寻找P的替代节点。规则是右分支最左边,或者 左分支最右边的节点 
216              * ---------------------(1) 
217              */  
218             if (p.left != null && p.right != null) {    
219                 Entry<K,V> s = successor(p);  
220                 p.key = s.key;  
221                 p.value = s.value;  
222                 p = s;  
223             }  
224       
225             //replacement为替代节点,如果P的左子树存在那么就用左子树替代,否则用右子树替代  
226             Entry<K,V> replacement = (p.left != null ? p.left : p.right);  
227       
228             /* 
229              * 删除节点,分为上面提到的三种情况 
230              * -----------------------(2) 
231              */  
232             //如果替代节点不为空  
233             if (replacement != null) {  
234                 replacement.parent = p.parent;  
235                 /* 
236                  *replacement来替代P节点 
237                  */  
238                 //若P没有父节点,则跟节点直接变成replacement  
239                 if (p.parent == null)  
240                     root = replacement;  
241                 //如果P为左节点,则用replacement来替代为左节点  
242                 else if (p == p.parent.left)  
243                     p.parent.left  = replacement;  
244               //如果P为右节点,则用replacement来替代为右节点  
245                 else  
246                     p.parent.right = replacement;  
247       
248                 //同时将P节点从这棵树中剔除掉  
249                 p.left = p.right = p.parent = null;  
250       
251                 /* 
252                  * 若P为红色直接删除,红黑树保持平衡 
253                  * 但是若P为黑色,则需要调整红黑树使其保持平衡 
254                  */  
255                 if (p.color == BLACK)  
256                     fixAfterDeletion(replacement);  
257             } else if (p.parent == null) {     //p没有父节点,表示为P根节点,直接删除即可  
258                 root = null;  
259             } else {      //P节点不存在子节点,直接删除即可  
260                 if (p.color == BLACK)         //如果P节点的颜色为黑色,对红黑树进行调整  
261                     fixAfterDeletion(p);  
262       
263                 //删除P节点  
264                 if (p.parent != null) {  
265                     if (p == p.parent.left)  
266                         p.parent.left = null;  
267                     else if (p == p.parent.right)  
268                         p.parent.right = null;  
269                     p.parent = null;  
270                 }  
271             }  
272         }  
273     static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {  
274             if (t == null)  
275                 return null;  
276             /* 
277              * 寻找右子树的最左子树 
278              */  
279             else if (t.right != null) {  
280                 Entry<K,V> p = t.right;  
281                 while (p.left != null)  
282                     p = p.left;  
283                 return p;  
284             }   
285             /* 
286              * 选择左子树的最右子树 
287              */  
288             else {  
289                 Entry<K,V> p = t.parent;  
290                 Entry<K,V> ch = t;  
291                 while (p != null && ch == p.right) {  
292                     ch = p;  
293                     p = p.parent;  
294                 }  
295                 return p;  
296             }  
297         }  
298     private void fixAfterDeletion(Entry<K,V> x) {  
299             // 删除节点需要一直迭代,知道 直到 x 不是根节点,且 x 的颜色是黑色  
300             while (x != root && colorOf(x) == BLACK) {  
301                 if (x == leftOf(parentOf(x))) {      //若X节点为左节点  
302                     //获取其兄弟节点  
303                     Entry<K,V> sib = rightOf(parentOf(x));  
304       
305                     /* 
306                      * 如果兄弟节点为红色----(情况3.1) 
307                      * 策略:改变W、P的颜色,然后进行一次左旋转 
308                      */  
309                     if (colorOf(sib) == RED) {       
310                         setColor(sib, BLACK);       
311                         setColor(parentOf(x), RED);    
312                         rotateLeft(parentOf(x));  
313                         sib = rightOf(parentOf(x));  
314                     }  
315       
316                     /* 
317                      * 若兄弟节点的两个子节点都为黑色----(情况3.2) 
318                      * 策略:将兄弟节点编程红色 
319                      */  
320                     if (colorOf(leftOf(sib))  == BLACK &&  
321                         colorOf(rightOf(sib)) == BLACK) {  
322                         setColor(sib, RED);  
323                         x = parentOf(x);  
324                     }   
325                     else {  
326                         /* 
327                          * 如果兄弟节点只有右子树为黑色----(情况3.3) 
328                          * 策略:将兄弟节点与其左子树进行颜色互换然后进行右转 
329                          * 这时情况会转变为3.4 
330                          */  
331                         if (colorOf(rightOf(sib)) == BLACK) {  
332                             setColor(leftOf(sib), BLACK);  
333                             setColor(sib, RED);  
334                             rotateRight(sib);  
335                             sib = rightOf(parentOf(x));  
336                         }  
337                         /* 
338                          *----情况3.4 
339                          *策略:交换兄弟节点和父节点的颜色, 
340                          *同时将兄弟节点右子树设置为黑色,最后左旋转 
341                          */  
342                         setColor(sib, colorOf(parentOf(x)));  
343                         setColor(parentOf(x), BLACK);  
344                         setColor(rightOf(sib), BLACK);  
345                         rotateLeft(parentOf(x));  
346                         x = root;  
347                     }  
348                 }   
349                   
350                 /** 
351                  * X节点为右节点与其为做节点处理过程差不多,这里就不在累述了 
352                  */  
353                 else {  
354                     Entry<K,V> sib = leftOf(parentOf(x));  
355       
356                     if (colorOf(sib) == RED) {  
357                         setColor(sib, BLACK);  
358                         setColor(parentOf(x), RED);  
359                         rotateRight(parentOf(x));  
360                         sib = leftOf(parentOf(x));  
361                     }  
362       
363                     if (colorOf(rightOf(sib)) == BLACK &&  
364                         colorOf(leftOf(sib)) == BLACK) {  
365                         setColor(sib, RED);  
366                         x = parentOf(x);  
367                     } else {  
368                         if (colorOf(leftOf(sib)) == BLACK) {  
369                             setColor(rightOf(sib), BLACK);  
370                             setColor(sib, RED);  
371                             rotateLeft(sib);  
372                             sib = leftOf(parentOf(x));  
373                         }  
374                         setColor(sib, colorOf(parentOf(x)));  
375                         setColor(parentOf(x), BLACK);  
376                         setColor(leftOf(sib), BLACK);  
377                         rotateRight(parentOf(x));  
378                         x = root;  
379                     }  
380                 }  
381             }  
382       
383             setColor(x, BLACK);  
384         }
View Code

四:LinkedHashMap

   HashMap对键值对的组织是无顺序的。遍历顺序不一定是按照插入顺序,所以如果想按照插入顺序来遍历结果的话用HashMap是不行的。为此,我们可以使用LinkedHashMap。

   与LinkedHashSet类似,LinkedHashMap也是维护了一个双向链表,记录元素的插入顺序,然后再根据元素值,采用hashcode()、equals()方法来存储元素值并实现元素的唯一性。双向链表将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同

第一种:通过Map.entrySet使用iterator遍历key和value

public void visit_1(HashMap<String,Integer> hm){
        Iterator<Map.Entry<String,Integer>> it = hm.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<String ,Integer> entry = it.next();
            String  key = entry.getKey();
            Integer value = entry.getValue();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

第二种:通过Key来遍历value

public void visit_2(HashMap<String,Integer> hm){
        for (String key:hm.keySet()){
            Integer value = hm.get(key);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5

第三种:通过Map.Entry遍历key和value

 public void visit_3(HashMap<String,Integer> hm){
        for(Map.Entry<String,Integer> entry:hm.entrySet()){
            String key = entry.getKey();
            Integer value = entry.getValue();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第四种:通过Map.keySet使用iterator遍历key和value

public void visit_4(HashMap<Integer,String> hm){
        long startTime = System.currentTimeMillis();
        Iterator<Integer> it = hm.keySet().iterator();
        while(it.hasNext()){
            Integer key = it.next();
            String value = hm.get(key);
        }
        System.out.println("visit_4 10000000 entry:"
                + (System.currentTimeMillis()-startTime) + " milli seconds");
    }
posted @ 2018-07-01 02:22  Coosee  阅读(350)  评论(0编辑  收藏  举报