`
anranran
  • 浏览: 29075 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java HashMap分析

阅读更多
JAVA HASHMAP的原理分析 一网友发贴:map原理,它是如何快速查找key的.
还是来整体看一下HashMap的结构吧. 如下图所示(图没画好),方框代表Hash桶,椭图代表桶内的元素,在这里就是Key-value对所组成Map.Entry对像.

如果有多个元索被Hash函数定位到同一个桶内,我们称之为hash冲突,桶内的元素组成单向链表.让我们看一下hashMap JDK源码(因篇幅关系,删除了部分代码与注释,感兴可以查看JDK1.6源码):
public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{
    static final int DEFAULT_INITIAL_CAPACITY = 16;
    static final int MAXIMUM_CAPACITY = 1 << 30;
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    transient Entry[] table;
    transient int size;
    int threshold;
    final float loadFactor;
    transient volatile int modCount;
    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);

        // Find a power of 2 >= initialCapacity
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;

        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
        table = new Entry[capacity];
        init();
    }

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

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

先介绍一下负载因子(loadFactor)和容量(capacity)的属性。其实一个 HashMap 的实际容量就 因子*容量,其默认值是 16(DEFAULT_INITIAL_CAPACITY)×0.75=12; 这个很重要,当存入HashMap的对象超过这个容量时,HashMap 就会重新构造存取表.

最重要的莫过于Put与Get方法.
我们先看put. 这里先说一下,HashMap的hash函数是对key对像的hashCode进行hash,并把Null keys always map to hash 0.这里也正好证明了为什么基本类型(int之类) 不能做KEY值。
参考put方法源码,首选判断Key是否为null,若为NULL,刚从0号散列桶内去寻找key为null的Entry,找到则用新的Value替换旧的Value值,并返回旧值.反之把当前Entry放入0号桶,0号桶内的其他Entry链接到当前Entry后面(参考Entry的next属性).

如果是非NULL值,其实已经很简单,根把hash结果找到相应的hash桶(当前桶),遍历桶内链表,如果找到与当前KEY值相同Entry,则替抱该Entry的value值为当前value值。否则用当前key-value构建Entry对像,并入当前桶内,桶内元素链到新Entry后面.与NULL思路相同.

到这里get方法,就不用多说了,首先用key的hashCode 进行hash(参考HashMap的hash方法),用所得值定位桶号.遍历桶内链表,找到该KEY值的Entry对像,返回VALUE.反不到,则返回NULL,简单着呢.

回到网友贴子上来,如何快速查找KEY? hashMap通示计算得的HASH值快速定位到元素所在的桶,这样就排除了绝大部分元素,遍历其内的小链表就很快了.如果用链表把所有元素链起来,时间可想而知.
HashMap唯一高明之处在于他的Hash算法(不太明白):

static int hash(int h) {
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
}.
另外 transient Entry[] table中的transient是什么意思,下一篇再说吧,欢迎拍砖.
3
1
分享到:
评论
1 楼 usiboy 2009-12-26  
这几天我也在研究HashMap,不过HashMap的精华在于算法和视图,那个Entry就是视图的表现方式,但还是不太明白设计这个Entry具体的用意是干什么的..

相关推荐

    java HashMap原理分析

    Java HashMap原理分析 Java HashMap是一种基于哈希表的数据结构,它的存储原理是通过将Key-Value对存储在一个数组中,每个数组元素是一个链表,链表中的每个元素是一个Entry对象,Entry对象包含了Key、Value和指向...

    自定义map实现java的hashmap

    通过以上分析,我们可以了解到实现一个自定义的HashMap涉及许多细节和技巧,包括哈希函数的设计、冲突解决策略的选择、以及性能优化等。在实际编程中,理解这些概念有助于我们更好地使用和定制HashMap,满足特定需求...

    疫苗:Java HashMap的死循环

    Java HashMap的死循环原因分析 HashMap是Java中一种常用的数据结构,它提供了快速的查找、插入和删除操作。然而,在多线程环境中使用HashMap可能会导致死循环的问题。下面我们来分析HashMap的死循环原因。 首先,...

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

    本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, `TreeMap`以及`HashTable`之间的区别。 #### 1. HashMap `HashMap`是一种基于哈希表实现的`Map`接口,提供了一个非同步的、允许使用`null`键和...

    Java8 HashMap的实现原理分析

    Java8之后新增挺多新东西,接下来通过本文给大家介绍Java8 HashMap的实现原理分析,对java8 hashmap实现原理相关知识感兴趣的朋友一起学习吧

    HashMap 分析

    HashMap是Java语言中非常常见的一种数据结构,主要用于存储键值对。在本分析中,我们将会详细探讨HashMap在不同负载因子(loadFactor)、循环次数(loop)、哈希表长度(maptablelen)和映射长度(maplen)等条件下...

    Java8HashMap键与Comparable接口编程开

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

    基于HashMap的用户标签处理兼Java中HashMap实现原理研究.pdf

    "基于HashMap的用户标签处理兼Java中HashMap实现原理研究" 本文研究了基于HashMap的用户标签处理方法,并对Java中HashMap的实现原理进行了深入研究。HashMap是一种高效的数据结构,可以快速地存储和检索数据。本文...

    词法分析器java

    ### 词法分析器Java知识点解析 #### 一、词法分析器简介 词法分析器(Lexical Analyzer),也称为扫描器或词法解析器,是编译器中的一个关键组件,负责将源代码字符流分解成一系列的有意义的词汇单元(Token)。...

    2022年Java中对HashMap的深度分析Java教程.docx

    本教程将深入分析2022年Java中HashMap的内部机制、关键属性和操作。 HashMap的核心属性包括容量(capacity)和负载因子(load factor)。容量是指HashMap可以存储的元素的最大数量,而负载因子则是HashMap在达到多...

    Java HashMap实现原理分析(一)

    Java HashMap是Java编程中常用的集合类之一,它提供了一种高效的方式来存储和检索键值对数据。HashMap的实现原理基于哈希表,它的核心是通过哈希函数将键(key)映射到一个数组的特定位置,从而实现快速访问。本文将...

    HashMap部分源码分析

    ### HashMap部分源码分析 #### 一、HashMap数据结构 ...通过以上分析可以看出,HashMap的实现充分利用了哈希算法的优势,同时巧妙地解决了哈希冲突的问题,使其成为Java中一个非常高效且实用的数据结构。

    HashMap源码分析

    HashMap 是 Java 中最常用的集合类之一,它是基于哈希表实现的,提供了高效的数据存取功能。HashMap 的核心原理是将键(key)通过哈希函数转化为数组索引,然后将键值对(key-value pair)存储在数组的对应位置。...

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

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

    深入理解Java之HashMap —— 03

    现在,我们来详细分析给定的文件中提到的HashMap的构造函数和操作流程: 1. **HashMap的构造函数**: HashMap的构造函数允许用户指定初始容量(initialCapacity)和负载因子(loadFactor)。如果初始容量小于0或...

    JAVA算法分析-很好的java思想

    本文将深入探讨“JAVA算法分析”,旨在帮助读者从深层次理解Java语言,并结合算法思想提升编程能力。 首先,Java语言为实现高效算法提供了良好的支持。其面向对象的特性使得代码更易于组织和复用,接口、抽象类和...

    HashMap死循环原因分析.docx

    HashMap是Java中常用的数据结构,但是它在多线程环境下可能会出现死循环的问题,使CPU占用率达到100%。这种情况是如何产生的呢?下面我们将从源码中一步一步地分析这种情况是如何产生的。 首先,我们需要了解...

    hashmap实现原理

    哈希映射(HashMap)是Java编程语言中广泛使用的数据结构之一,主要提供键值对的存储和查找功能。HashMap的实现基于哈希表的概念,它通过计算对象的哈希码来快速定位数据,从而实现了O(1)的平均时间复杂度。在深入...

    Java HashMap三种循环遍历方式及其性能对比实例分析

    Java HashMap三种循环遍历方式及其性能对比实例分析 Java HashMap是一种常用的数据结构,在Java编程中经常被使用。HashMap提供了三种循环遍历方式,即for each map.entrySet()、显示调用map.entrySet()的集合迭代器...

    在Java8与Java7中HashMap源码实现的对比

    二、Java 7中HashMap的源码分析 1. 构造函数:在Java 7中,HashMap的构造函数会根据传入的初始容量(initialCapacity)和加载因子(loadFactor)计算阈值(threshold),阈值等于初始容量乘以加载因子。当HashMap中的元素...

Global site tag (gtag.js) - Google Analytics