天天看點

HashMap、HashTable和TreeMap詳解概述HashMapHashTableTreeMap示例

概述

        HashMap、HashTable和TreeMap 是Map接口下三個重要的集合類。

        樹預設的是紅黑樹算法

HashMap、HashTable和TreeMap詳解概述HashMapHashTableTreeMap示例

HashMap

        預設的初始化大小是16

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
           

        最大容量是2的30次方

static final int MAXIMUM_CAPACITY = 1 << 30;
           

        預設的擴充因子是0.75。比如在大小為16時,如果存儲的資料達到了16*0.75=12時,就會擴充容量

static final float DEFAULT_LOAD_FACTOR = 0.75f;
           

        有一個node内部類,判斷node相等,必須是key的hashcode和value的hashcode同時相等。

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;
        }
    }
           

HashTable

        預設大小是11

public Hashtable() {
        this(11, 0.75f);
    }
           

        預設的容量因子是0.75

public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }
           

        它裡面的每一個操作方法都有synchronized修飾,用以保證同步

public synchronized boolean contains(Object value) {
        if (value == null) {
            throw new NullPointerException();
        }

        Entry<?,?> tab[] = table;
        for (int i = tab.length ; i-- > 0 ;) {
            for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }
           

        添加一項時

public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }
           

        其中addEntrty。

private void addEntry(int hash, K key, V value, int index) {
        modCount++;

        Entry<?,?> tab[] = table;
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();

            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>) tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }
           

        删除

public synchronized V remove(Object key) {
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>)tab[index];
        for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                modCount++;
                if (prev != null) {
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                count--;
                V oldValue = e.value;
                e.value = null;
                return oldValue;
            }
        }
        return null;
    }
           

        toString()方法将鍵值對都列印出來

public synchronized String toString() {
        int max = size() - 1;
        if (max == -1)
            return "{}";

        StringBuilder sb = new StringBuilder();
        Iterator<Map.Entry<K,V>> it = entrySet().iterator();

        sb.append('{');
        for (int i = 0; ; i++) {
            Map.Entry<K,V> e = it.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key.toString());
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value.toString());

            if (i == max)
                return sb.append('}').toString();
            sb.append(", ");
        }
    }
           

        屬性都有volatile關鍵字修飾

private transient volatile Set<K> keySet;
    private transient volatile Set<Map.Entry<K,V>> entrySet;
    private transient volatile Collection<V> values;
           

TreeMap

        添加時

public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }
           

        裡面的紅黑樹機制:

// Red-black mechanics
    private static final boolean RED   = false;
    private static final boolean BLACK = true;
           
K key;
        V value;
        Entry<K,V> left;
        Entry<K,V> right;
        Entry<K,V> parent;
        boolean color = BLACK;
           

        取出第一個

final Entry<K,V> getFirstEntry() {
        Entry<K,V> p = root;
        if (p != null)
            while (p.left != null)
                p = p.left;
        return p;
    }
           

        取出最後一個

final Entry<K,V> getLastEntry() {
        Entry<K,V> p = root;
        if (p != null)
            while (p.right != null)
                p = p.right;
        return p;
    }
           

示例

        TreeMap相對于HashMap,key是有序排列

public static void main(String[] args) {
		Map<String,String> map = new TreeMap<>();
		map.put("a", "aaa");
		map.put("b", "bbb");
		map.put("c", "ccc");
		map.put("2", "222");
		map.put("5", "555");
		map.put("e", "eee");
		map.put("d", "ddd");
		
		Set<String> sets = map.keySet();
		for(String s : sets){
			System.out.println(s+" : " +map.get(s));
		}
		
		System.out.println("=================================");
		
		Map<String,String> map2 = new HashMap<>();
		map2.put("c", "ccc");
		map2.put("e", "eee");
		map2.put("d", "ddd");
		map2.put("2", "222");
		map2.put("5", "555");
		map2.put("a", "aaa");
		map2.put("b", "bbb");
		
		Set<String> sets2 = map2.keySet();
		for(String s : sets2){
			System.out.println(s+" : " +map2.get(s));
		}
	}
           

        運作結果是:

2 : 222
5 : 555
a : aaa
b : bbb
c : ccc
d : ddd
e : eee
=================================
a : aaa
2 : 222
b : bbb
c : ccc
d : ddd
e : eee
5 : 555