JDK - HashMap

来源:互联网 发布:中万网络工资怎么样 编辑:程序博客网 时间:2024/05/21 09:57

HashMap是以数组的形式存放,存放内容的方式,根据当前key的(经过特殊处理)hashCode来决定,当前对象存储的位置。获取值时在通过(经过特殊处理)hashCode进行取值,而不需要遍历总个数组来获取,这也就是为什么hashMap性能高的原因。

   但值得注意的一点就是,hashCode不一定会唯一,而这时怎么做到的,这也就是为什么称HashMap 为 链表散列,因为在数组里面存储的是一个Entry(内部类对象 ,对像其中有一个Entry<K,V>  next的对象,这个对象就是最新的,hashCode相冲突的保存到这个对象最后,这个是无尽的。

  而我们怎么才能使HashMap性能达到最大化了,首先得说他怎么存储,在存储过程中会做哪些处理,和对源码的分析。

 一抓住会影响到性能的点

第一个性能点resize() ,当我们使用默认的HashMap 时分配的空间时(16), 当我们超过时threshold =DEFAULT_INITIAL_CAPACITY16 * DEFAULT_LOAD_FACTOR0.75f), 

if (size++ >= threshold)

会重新分配空间(2 * table.length),然后将以前内容,通过hashCode重新指定存储位置。所以在当我们知道的大概大小的情况下,不使用默认 new HashMap(),而是用new HashMap(length);

下面是主要JDK源码 

1.

   public V put(K key, V value) {

        if (key == null)

            return putForNullKey(value);

        int hash = hash(key.hashCode());

        int i = indexFor(hash, table.length);

        for (Entry<K,V> e = table[i]; e != null; e = e.next) {

            Object k;

            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

                V oldValue = e.value;

                e.value = value;

                e.recordAccess(this);

                return oldValue;

            }

        }

        modCount++;

        addEntry(hash, key, value, i);

        return null;

}

2. 

void addEntry(int hash, K key, V value, int bucketIndex) {

     Entry<K,V> e = table[bucketIndex];

        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);

        if (size++ >= threshold)

            resize(2 * table.length);

 }

3.

void resize(int newCapacity) {

        Entry[] oldTable = table;

        int oldCapacity = oldTable.length;

        if (oldCapacity == MAXIMUM_CAPACITY) {

            threshold = Integer.MAX_VALUE;

            return;

        }

        Entry[] newTable = new Entry[newCapacity];

        transfer(newTable);

        table = newTable;

        threshold = (int)(newCapacity * loadFactor);

}



TestHashMap.java 可执行文件

import java.util.HashMap;
import java.util.Map;    
@SuppressWarnings("unchecked")
public class TestHashMap<K,V> {
    static final int DEFAULT_INITIAL_CAPACITY = 16;
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    static final int MAXIMUM_CAPACITY = 1 << 30;
    int threshold;
    final float loadFactor;
    transient int size;
    transient Entry[] table;
    public TestHashMap() {
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        this.loadFactor = DEFAULT_LOAD_FACTOR;
    }
    public static void main(String[] args) {
        TestHashMap hashMap = new TestHashMap();
         System.out.println(hashMap.put("123", "asdasd"));
         System.out.println(hashMap.get("123"));
         new HashMap();
    }
    public V put(K key,V value) {
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i];e != null;e = e.next) {
             Object k ;
             if (e.hash == hash && ((k = e.key) == key) && key.equals(k) ) {
                   V oldValue = e.value;
                   e.value = value;
                   return oldValue;
             }
        }
        this.addEntry(hash,key, value,i);
        return value;
    }
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }
    private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }
    private void addEntry(int hash,K key,V value,int bucketIndex) {
        Entry e = table[bucketIndex];
        table[bucketIndex] = new Entry<K, V>(hash,key,value,e);
        if (size ++ >= threshold) {
            resize(table.length * 2);
        }
    }  
    void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }
    void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
    }
    static int indexFor(int h, int length) {
        return h & (length-1);
    }
    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    static class  Entry<K, V> implements Map.Entry<K, V>{
        final K key;
        V value;
        Entry<K,V> next;
        final int hash;
        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }
      
        public final K getKey() {
        
            return key;
        }

    
        public final V getValue() {
            return value;
        }

        
        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
        
        
    }
    
 
}



原创粉丝点击