码迷,mamicode.com
首页 > 其他好文 > 详细

HashMap源码分析jdk1.6

时间:2018-03-07 00:58:09      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:技术分享   imp   ati   构造   一点   cap   method   改版   rem   

 1、定义

public interface Map<K,V> {
    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);
    V put(K key, V value);
    V remove(Object key);
    void putAll(Map<? extends K, ? extends V> m);
    void clear();
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();
    interface Entry<K,V> {
       V getValue();
       V setValue(V value);
        boolean equals(Object o);
        int hashCode();
    }
    boolean equals(Object o);
    int hashCode();
}

hash是“散列”:hash就是通过散列算法,将一个任意长度关键字转换为一个固定长度的散列值,但是有一点要指出的是,不同的关键字可能会散列出相同的散列值

2、HashMap类

public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable

3.底层存储

// 默认初始容量为16,必须为2的n次幂
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    // 最大容量为2的30次方
    static final int MAXIMUM_CAPACITY = 1 << 30;

    // 默认加载因子为0.75f
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    // Entry数组,长度必须为2的n次幂
    transient Entry[] table;

    // 已存储元素的数量
    transient int size ;

    // 下次扩容的临界值,size>=threshold就会扩容,threshold等于capacity*load factor
    int threshold;

    // 加载因子
    final float loadFactor ;

Entry数组

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key ; 
        V value;
        Entry<K,V> next; // 指向下一个节点
        final int hash;

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

        public final boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public final int hashCode() {
            return (key ==null   ? 0 : key.hashCode()) ^
                   ( value==null ? 0 : value.hashCode());
        }

        public final String toString() {
            return getKey() + "=" + getValue();
        }

        // 当向HashMap中添加元素的时候调用这个方法,这里没有实现是供子类回调用
        void recordAccess(HashMap<K,V> m) {
        }

        // 当从HashMap中删除元素的时候调动这个方法 ,这里没有实现是供子类回调用
        void recordRemoval(HashMap<K,V> m) {
        }
}

技术分享图片

HashMap采用将相同的散列值存储到一个链表中,也就是说在一个链表中的元素他们的散列值绝对是相同的

4.构造方法

private void putAllForCreate(Map<? extends K, ? extends V> m) {
      for(Iterator<?extendsMap.Entry<?extendsK, ?extendsV>> i = m.entrySet().iterator(); i.hasNext(); ) {
            Map.Entry<? extends K, ? extends V> e = i.next();
            putForCreate(e.getKey(), e.getValue());
        }
    }

    /**
     * This method is used instead of put by constructors and
     * pseudoconstructors (clone, readObject).  It does not resize the table,
     * check for comodification, etc.  It calls createEntry rather than
     * addEntry.
     */
    private void putForCreate(K key, V value) {
        int hash = (key == null) ? 0 : 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 != null && key.equals(k)))) {
                e. value = value;
                return;
            }
        }

        createEntry(hash, key, value, i);
    }
   
   void createEntry(int hash, K key, V value, int bucketIndex) {
       Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        size++;
}

5、增加

public V put(K key, V value) {
        // 如果key为null,调用putForNullKey方法进行存储
        if (key == null)
            return putForNullKey(value);
        // 使用key的hashCode计算key对应的hash值
        int hash = hash(key.hashCode());
        // 通过key的hash值查找在数组中的index位置
        int i = indexFor(hash, table.length );
        // 取出数组index位置的链表,遍历链表找查看是有已经存在相同的key
        for (Entry<K,V> e = table [i]; e != null; e = e. next) {
            Object k;
            // 通过对比hash值、key判断是否已经存在相同的key
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                // 如果存在,取出当前key对应的value,供返回
                V oldValue = e. value;
                // 用新value替换之旧的value
                e. value = value;
                e.recordAccess( this);
                // 返回旧value,退出方法
                return oldValue;
            }
        }

        // 如果不存在相同的key
        // 修改版本+1
        modCount++;
        // 在数组i位置处添加一个新的链表节点
        addEntry(hash, key, value, i);
        // 没有相同key的情况,返回null
        return null;
    }

    private V putForNullKey(V value) {
        // 取出数组第1个位置(下标等于0)的节点,如果存在则覆盖不存在则新增,和上面的put一样不多讲,
        for (Entry<K,V> e = table [0]; e != null; e = e. next) {
            if (e.key == null) {
                V oldValue = e. value;
                e. value = value;
                e.recordAccess( this);
                return oldValue;
            }
        }
        modCount++;
        // 如果key等于null,则hash值等于0
        addEntry(0, null, value, 0);
        return null;
}

hash函数

 

HashMap源码分析jdk1.6

标签:技术分享   imp   ati   构造   一点   cap   method   改版   rem   

原文地址:https://www.cnblogs.com/L-a-u-r-a/p/8520002.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!