`

读HashMap源码

阅读更多
//先看构造函数
public HashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

  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;
        threshold = initialCapacity;
        init();
    }



 public HashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        inflateTable(threshold);

        putAllForCreate(m);
    }


public V put(K key, V value) {
        //如果Entry[]数组为空则初始化
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
	//允许key为null
        if (key == null)
            return putForNullKey(value);
	//计算hash值
        int hash = hash(key);
	//计算应为位于entry数组的角标位置
        int i = indexFor(hash, table.length);
	//这里循环遍历当前的桶中是否有key值和传入的key值相等。
	//从这里也可以看出如果计算hash有大量值相等那么效率将会降低
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
	    //如果hash值相等并且key值相等
            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;
    }
//填充Entry数组
 private void inflateTable(int toSize) {
        // Find a power of 2 >= toSize
        int capacity = roundUpToPowerOf2(toSize);
        //临界值为capacity*loadFactor
        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
        table = new Entry[capacity];
        initHashSeedAsNeeded(capacity);
    }
//null键
private V putForNullKey(V value) {
        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++;
        addEntry(0, null, value, 0);
        return null;
    }

void addEntry(int hash, K key, V value, int bucketIndex) {
        //如果size到达threshold并且table[bucketIndex]位置上已经有值了
        if ((size >= threshold) && (null != table[bucketIndex])) {
	  //以两倍长度扩容
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }



 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];
	//将原来的复制newTable
        transfer(newTable, initHashSeedAsNeeded(newCapacity));
        table = newTable;
        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
    }

//重新构建整个Entry[]数组
void transfer(Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e : table) {
            while(null != e) {
                Entry<K,V> next = e.next;
                if (rehash) {
                    e.hash = null == e.key ? 0 : hash(e.key);
                }
                int i = indexFor(e.hash, newCapacity);
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            }
        }
    }

//创建entry将旧的entry位于新的entrt的next
 void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }


public void putAll(Map<? extends K, ? extends V> m) {
        int numKeysToBeAdded = m.size();
        if (numKeysToBeAdded == 0)
            return;
         //如果table为空则初始化
        if (table == EMPTY_TABLE) {
            inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
        }

      
        if (numKeysToBeAdded > threshold) {
            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
            if (targetCapacity > MAXIMUM_CAPACITY)
                targetCapacity = MAXIMUM_CAPACITY;
            int newCapacity = table.length;
            while (newCapacity < targetCapacity)
                newCapacity <<= 1;
            if (newCapacity > table.length)
                resize(newCapacity);
        }

        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
    }



//根据key获取值
 public V get(Object key) {
        //获取null键的值
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }

 //null键永远在table[0]的位置。
 private V getForNullKey() {
        if (size == 0) {
            return null;
        }
	//在table[0]处取null键
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }


 final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }
        //计算hash值
        int hash = (key == null) ? 0 : hash(key);
        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 != null && key.equals(k))))
                return e;
        }
        return null;
    }

 static int indexFor(int h, int length) {
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
    }


//根据key删除
 public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);
        return (e == null ? null : e.value);
    }

final Entry<K,V> removeEntryForKey(Object key) {
        if (size == 0) {
            return null;
        }
        int hash = (key == null) ? 0 : hash(key);
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                modCount++;
                size--;
		//当前元素恰好在table[i]上的第一个元素
                if (prev == e)
                    table[i] = next;
                else
                    prev.next = next;
                e.recordRemoval(this);
                return e;
            }
            prev = e;
            e = next;
        }

        return e;
    }


//返回Map.entry的set视图
 public Set<Map.Entry<K,V>> entrySet() {
        return entrySet0();
    }

private Set<Map.Entry<K,V>> entrySet0() {
        Set<Map.Entry<K,V>> es = entrySet;
        return es != null ? es : (entrySet = new EntrySet());
    }

private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return newEntryIterator();
        }
        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<K,V> e = (Map.Entry<K,V>) o;
            Entry<K,V> candidate = getEntry(e.getKey());
	    //candidate.equals(e)用于判断他们的值是否相等
            return candidate != null && candidate.equals(e);
        }
        public boolean remove(Object o) {
            return removeMapping(o) != null;
        }
        public int size() {
            return size;
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

final Entry<K,V> removeMapping(Object o) {
        if (size == 0 || !(o instanceof Map.Entry))
            return null;

        Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
        Object key = entry.getKey();
        int hash = (key == null) ? 0 : hash(key);
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (e.hash == hash && e.equals(entry)) {
                modCount++;
                size--;
                if (prev == e)
                    table[i] = next;
                else
                    prev.next = next;
                e.recordRemoval(this);
                return e;
            }
            prev = e;
            e = next;
        }

        return e;
    }

 Iterator<Map.Entry<K,V>> newEntryIterator()   {
        return new EntryIterator();
    }

 private abstract class HashIterator<E> implements Iterator<E> {
        Entry<K,V> next;        // next entry to return
        int expectedModCount;   // For fast-fail
        int index;              // current slot
        Entry<K,V> current;     // current entry

        HashIterator() {
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                Entry[] t = table;
		//找到在entry中第一个值
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        }

        public final boolean hasNext() {
            return next != null;
        }

        final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();
            //如果当前链表中已经没有下一个了从数组中找
            if ((next = e.next) == null) {
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
            current = e;
            return e;
        }

        public void remove() {
            if (current == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount;
        }
    }
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
    }

//返回key的set视图
 public Set<K> keySet() {
        Set<K> ks = keySet;
        return (ks != null ? ks : (keySet = new KeySet()));
    }

private final class KeySet extends AbstractSet<K> {
        public Iterator<K> iterator() {
            return newKeyIterator();
        }
        public int size() {
            return size;
        }
        public boolean contains(Object o) {
            return containsKey(o);
        }
        public boolean remove(Object o) {
            return HashMap.this.removeEntryForKey(o) != null;
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

  public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

private final class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

//返回value视图
 public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null ? vs : (values = new Values()));
    }

  private final class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return newValueIterator();
        }
        public int size() {
            return size;
        }
        public boolean contains(Object o) {
            return containsValue(o);
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

public boolean containsValue(Object value) {
        if (value == null)
            return containsNullValue();

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


private boolean containsNullValue() {
        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (e.value == null)
                    return true;
        return false;
    }

private final class ValueIterator extends HashIterator<V> {
        public V next() {
            return nextEntry().value;
        }
    }

//清空该map
public void clear() {
        modCount++;
        Arrays.fill(table, null);
        size = 0;
    }


/**
总结:HashMap是数组加链表来实现的,非安全的,允许null值和null键。
在插入数据的时候会计算键的hash值,然后根据hash值放在数组中。
如果数组中有元素了,则把该元素放在数组上的第一个然后next指向原本的一个。
所以table[index]上永远都是最新插入的键值对。

HashMap和Hashtable的区别:
HashMap允许null值和null键。Hashtable不允许。
Hashtable是线程安全的。
*/
分享到:
评论

相关推荐

    Hash Map for geeks_hashmap_Geeks_源码

    标题中的“Hash Map for geeks_hashmap_Geeks_源码”显然指的是一个关于哈希映射(HashMap)的学习资源,特别针对极客和普通程序员。哈希映射是一种数据结构,它允许我们以O(1)的时间复杂度进行插入、删除和查找操作...

    mybatis读缓存源码demo

    本篇将通过分析“mybatis读缓存源码demo”来探讨这两个缓存层次的工作原理和实现。 一级缓存是 SqlSession 级别的,它是默认开启的。每次执行 CRUD(创建、读取、更新、删除)操作时,MyBatis 都会将结果存储在当前...

    最全的Java面试题、读书笔记、面试经验

    java面试 【作品名称】:最全的Java面试题、读书笔记、面试经验 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计... * [HashMap源码剖析](Part2/JavaSE/HashMap源码剖析.md)

    java7hashmap源码-Concurrency:这是用来学习java多线程的

    hashmap源码 concurrency 项目介绍 并发编程 可见性-volatile 通过内存屏障和禁止重排序优化实现 1.对volatile变量写操时,会在写操作后加入一条store屏障指令,将本地内存中的共享变量值刷新到主内存 2.对volatile...

    通过代码证明HashMap是线程不安全的(只用了一个Java文件)

    本篇文章将通过分析`HashMap`的源码以及编写一个简单的测试程序来证明这一点。 首先,我们要理解什么是线程安全。线程安全是指在多线程环境中,一个类或方法可以被多个线程同时访问而不会导致数据不一致或者意外的...

    jdk源码学习

    例如,`java.util`包包含了ArrayList、HashMap等常用数据结构;`java.io`包提供了文件读写和流处理的功能;`java.nio`包则引入了非阻塞I/O,提高了性能。 3. **反射(Reflection)**:Java反射API允许程序在运行时...

    Jdk1.8源码,包含sun的源码

    再比如,集合框架的`HashMap`和`TreeMap`等也进行了优化,提高了性能和线程安全性。 总而言之,JDK 1.8源码是一份宝贵的资源,它揭示了Java平台的内部运作细节,对于提升开发者的技术水平和解决问题的能力有着不可...

    HashMap-treeifyBin()源码简读(JDK1.8)

    HashMap的treeifyBin()方法源码 final void treeifyBin(Node[] tab, int hash) { //定义几个变量,n是数组长度,index是索引 int n, index; Node e; //这里的tab指的是本HashMap中的数组,n为数字长度,如果数组...

    java初学者学习源码

    Java编程语言是全球广泛使用的开发语言之一,尤其适合初学者入门。这个"java初学者学习源码"压缩包提供...切记,实践是检验理论的最好方式,所以不仅要读懂源码,更要动手编写自己的Java程序,不断巩固和提升编程技能。

    疯狂Java源码

    在Java编程中,源码是程序的基础,它由程序员用人类可读的编程语言编写,包含了程序的逻辑和结构。学习源码有助于我们了解如何组织代码、设计类和接口、处理异常、实现多线程、以及利用Java的面向对象特性。在这个...

    学习Java必须读懂两套源代码

    例如,集合框架中的ArrayList和LinkedList是如何实现动态扩容的,HashMap的散列策略如何避免碰撞,以及线程同步的底层机制如synchronized关键字的工作原理等。 其次,理解JVM的源代码,包括类加载、字节码解析、...

    电话本软件及源码(JAVA)

    良好的代码组织结构可以使代码更易读、易维护。可能会看到不同的类负责不同的功能,如ContactManager类负责整体业务逻辑,DAO(Data Access Object)类处理数据库交互,UI类负责界面展示等。 总的来说,这款JAVA...

    数据结构源码

    数据结构是计算机科学中的核心概念,它涉及到如何在内存中有效地组织和管理数据,以便进行高效的...此外,源码还可以帮助你学习如何编写清晰、可读的代码,遵循良好的编程规范,这些都是成为一名优秀程序员的关键要素。

    JDK1.8源码完整版

    Lambda表达式是JDK1.8的一个重要特性,它简化了对匿名内部类的使用,使得代码更加简洁和易读。通过使用 Lambda,我们可以将函数作为参数传递,或者将函数直接定义为方法体。这在处理集合操作时尤其有用,配合Stream ...

    上百款java源码

    通过这种方式,你可以提高自己的编程习惯,学会如何写出易读、易维护的代码。 其次,源码包可能涵盖了多种Java应用领域,如Web开发(例如Spring Boot、Struts或Servlets)、数据处理(如JDBC、Hibernate或MyBatis)...

    数据结构与问题求解——java语言描述 源码

    在Java中,这些数据结构可以通过内置类如ArrayList、LinkedList、Stack、Queue、HashSet和HashMap等来实现。例如,`Graph.java`文件很可能包含了图的实现,可能包括邻接矩阵或邻接表等表示方法,以及图的遍历算法如...

    Map-main-源码.rar

    HashMap是非线程安全的,适合于高并发环境下的读操作。 二、TreeMap TreeMap使用红黑树作为底层数据结构,提供了有序的键值对存储。红黑树是一种自平衡的二叉查找树,它保证了插入、删除和查找的时间复杂度都是O...

    一些java的源码

    源码是程序员用人类可读的语言编写的程序文本,它包含了所有关于如何执行特定任务的指令。在Java中,源码通常以`.java`为扩展名。在给定的压缩包文件中,虽然没有提供具体的源码文件,但从标题和描述中我们可以推测...

    java面向对象编程源码

    通过分析和实践孙卫琴的源码,开发者不仅能掌握Java面向对象编程的基本概念,还能提升对实际问题的解决能力,进一步理解面向对象设计原则,如 SOLID 原则,以及如何写出更高效、可读和可维护的代码。同时,这样的...

    毕向东 笔记源码

    源码,即编程语言的原始代码,是程序员用人类可读的形式编写的程序,未经过编译器转换成机器语言。在Java中,源代码以.java文件的形式存在。通过阅读和分析源码,我们可以了解程序的设计思路、实现方法以及编程技巧...

Global site tag (gtag.js) - Google Analytics