`
cjsmq
  • 浏览: 14526 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java Map HashMap

阅读更多
HashMap 是以key-value来存储的数据结构。
底层的实现是:entry类型的数组。将key-value封装成entry对象。对于这种数据结构我们也称之为 散列链表。

HashMap 定义源码如下:
public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{

    /**
     * The default initial capacity - MUST be a power of two.
     */
    //初始最大容量 必须是2的次幂
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * The load factor used when none specified in constructor.
     **/
    //负载因子 表示散表的装满程度。
    //如HashMap 的size>最大容量 * 0.75;表示HashMap实际容量已满,需要扩容
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
   //即是HashMap底层实现: 是以Entry 类型的数组;
    transient Entry[] table;

    /**
     * The number of key-value mappings contained in this identity hash map.
     */
    //存储的有效数据 key-value(会被封装成Entry对象) 个数
    transient int size;
  
    /**
     * The next size value at which to resize (capacity * load factor).
     * @serial
     */
    //该变量定义作为 该Map是否扩容的依据 ;即是实际容量。
     //threshold = 最大容量*负载因子;
     //如果size > threshold ;容器将会被扩容2倍,下面会讲到扩容。
    int threshold;
 


HashMap 的构造方法:
   
  //无参构造函数
   public HashMap() {
        //默认负载因子 0.75
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        //实际容量 16*0.75
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        //Entry类型的数组 
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
     }


再来看看 内部定义Entry对象:

    
static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;  //hashMap key
        V value;      //hashMap value
        final int hash;  //通过对 key.hashCode()的值进行hash运算得出的值
        Entry<K,V> next; //下一entry对象的引用。



先看下HashMap的数据结构图:



来看看HashMap put方法:


    
 public V put(K key, V value) {
        if (key == null)
             //对key==null时处理
	    return putForNullKey(value);
        // 对key的hashCode值进行hash运算
        int hash = hash(key.hashCode());
        // 得到的hash值与数组长度进行 & (位) 运算
         // 得到的i即是数组中对应的下标位置
        int i = indexFor(hash, table.length);
        //对该entry数组下标为i的位置上entry对象的链表,进行遍历。
         //如若存在该数据 则替换原先的value。
        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;
    }
    
    //key==null的处理,定义一个常量NULL_KEY的Object对象,对它进行hash运算。
    private V putForNullKey(V value) {
        int hash = hash(NULL_KEY.hashCode());
        int i = indexFor(hash, table.length);

        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            if (e.key == NULL_KEY) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, (K) NULL_KEY, value, i);
        return null;
    }
    
    //hash运算方法
     static int hash(int h) {
       return useNewHash ? newHash(h) : oldHash(h);
    }

    //具体的hash算法
    private static int oldHash(int h) {
        h += ~(h << 9);
        h ^=  (h >>> 14);
        h +=  (h << 4);
        h ^=  (h >>> 10);
        return h;
    }
    
    //hash 与 数组长度 & (位)运算。得到数组对应下标的位置
    static int indexFor(int h, int length) {
        return h & (length-1);
    }

    void addEntry(int hash, K key, V value, int bucketIndex) {
        //提取原先数组下标下的entry对象
         //如果该数组下标下没有entry,则e==null
        Entry<K,V> e = table[bucketIndex];
        //更改数组下标引用至新的entry对象
         //并将新的entry对象的next指向数组下标原先的entry对象
         //如若该数组下标不存在entry,则next引用为空。
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        //鉴于查找效率的考虑,HashMap 的size > 实际容量时,则扩容。
        if (size++ >= threshold)
            //entry数组扩容2倍。
            resize(2 * table.length);
    }
    
    //entry数组扩容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];
        //数组扩容后,所有entry元素需要重新计算数组下标位置。
         //生成新的散列链表
         transfer(newTable);
        table = newTable;
        //重新计算实际容量
        threshold = (int)(newCapacity * loadFactor);
    }
    
    //遍历hashMap下所有entry 通过 indexFor 方法重新计算数组位置。
    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);
            }
        }
    }



HashMap get方法:

  
   //get方法与put方法中处理是否存在该数据是类似的。
   public V get(Object key) {
	if (key == null)
             // key==null的处理
	    return getForNullKey();
        int hash = hash(key.hashCode());
        //hash 、indexFor方法确定数组位置上entry的链表,进行遍历。
        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;
    }
  • 大小: 62.3 KB
分享到:
评论

相关推荐

    自定义map实现java的hashmap

    在Java编程中,HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的存储功能,具有快速存取和高效查找的特点。HashMap基于哈希表(也称为散列表)原理,通过键对象的哈希码来定位元素,进而实现O(1)...

    java中HashMap,LinkedHashMap,TreeMap,HashTable的区别

    ### Java中HashMap, LinkedHashMap, TreeMap,HashTable的区别 在Java编程语言中,`Map`接口是集合框架中的一个重要组成部分,用于存储键值对。本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, ...

    java中HashMap详解.pdf

    Java中的HashMap是一种基于散列机制的Map接口的实现,它允许我们存储键值对。键是唯一的,而值可以重复。HashMap在处理数据时非常高效,因为其操作的时间复杂度接近于O(1)。这是通过使用散列函数将键映射到相应的...

    Java中HashMap的工作机制

    在Java中,HashMap是一种广泛使用的数据结构,它基于哈希表的Map接口实现。哈希表是一种通过哈希过程将键映射到特定位置的数据结构,该位置存储了键对应的值。在详细探讨Java中HashMap的工作机制之前,首先需要理解...

    利用Java的HashMap 改造C++ 的hash_map

    结合Java的HashMap中的一些优点,改进了C++ 的hash_map。 详细说明见我的博客:http://blog.csdn.net/mdj67887500/article/details/6907702

    js 版 java hashmap

    Java的HashMap是一个基于哈希表的Map接口实现,提供快速的插入、删除和查找操作,平均时间复杂度为O(1)。下面我们将详细探讨JavaScript中如何实现类似Java HashMap的功能,以及这个实现可能包含的关键知识点。 1. *...

    java循环Map java迭代Map

    Map a = new HashMap(); //方法一 Iterator it = a.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = (Map.Entry) it.next(); System.out.println(pairs.getValue()); } //以下方法需要jdk5以上...

    Java HashMap类详解

    Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework ...

    Map与HashMap

    《java编程思想》,Map结合HashMap获取键相关联的值

    Java-HashMap.rar_hashmap_java hashmap

    在Java编程语言中,`HashMap`是`java.util`包中的一个核心类,它属于集合框架的一部分,主要用于存储键值对的数据结构。`HashMap`基于哈希表(散列表)实现,提供了快速的插入、删除和查找操作,平均时间复杂度为O(1...

    java map 实现缓存技术

    在Java中,我们通常使用HashMap、ConcurrentHashMap等Map实现来创建缓存。这些数据结构具有O(1)的平均时间复杂度,能够快速地查找和存储元素,非常适合缓存应用场景。 在给定的描述中提到了"毫秒计算",这涉及到...

    java Pojo转Map

    Map接口则是Java集合框架的一部分,它提供了键值对的数据存储方式,方便数据的存取。将Pojo对象转换为Map,可以简化数据处理过程,尤其是在JSP页面上展示数据时,Map的灵活性更加突出。本文将详细介绍如何实现Java中...

    java HashMap原理分析

    在Java中,HashMap广泛应用于Set、Map等容器中,用于快速根据Key找到元素。例如,Set的contains方法和Map的get方法都是通过Key去查找的。 然而,HashMap的实现也存在一些问题,例如哈希碰撞问题和equals方法的调用...

    Java里多个Map的性能比较(TreeMap、HashMap、ConcurrentSkipListMap)

    在Java编程中,Map接口是用于存储键值对的数据结构,而Java提供了多种Map的实现,包括TreeMap、HashMap和ConcurrentSkipListMap。本文主要比较了这三种Map的性能,尤其是在插入和查找操作上的效率。 1. **TreeMap**...

    Java8HashMap键与Comparable接口编程开

    在Java编程中,HashMap是Java集合框架中的一个重要成员,它提供了高效的存储和检索对象的机制。在Java 8中,HashMap有一些重要的优化和改进,尤其是对于键(Key)的处理方式。这里我们将深入探讨Java 8 HashMap如何...

    java Map实现的cache manager,定时清除缓存里面的值

    java Map实现的cache manager,定时清除缓存里面的值,使数据一致保持最新

    JAVA hashmap 负载因子为什么是0.75,官方解释

    java hashmap 扩容因子为什么是0.75,官方给出的解释

    java在hashmap初始化时赋初值过程解析

    Java 在 HashMap 初始化时赋初值过程解析 Java 中的 HashMap 是一种常用的数据结构,一般用来做数据字典或者 Hash 查找的容器。在初始化并赋初值时,我们通常使用 `HashMap, Object&gt; map = new HashMap();` 的方式...

    Java中HashMap详解(通俗易懂).doc

    Java中的HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的高效存储和访问。HashMap基于哈希表(也称为散列表)原理工作,它允许用户通过键(Key)快速查找对应的值(Value)。在HashMap中,键和值...

    java中hashmap容量的初始化实现

    "Java中HashMap容量的初始化实现" Java中HashMap容量的初始化实现是非常重要的,特别是在大规模数据处理时。HashMap的容量初始化可以极大地影响程序的性能。在本文中,我们将详细介绍Java中HashMap容量的初始化实现...

Global site tag (gtag.js) - Google Analytics