java数据结构之HashMap

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nongfuyumin/article/details/88538861

                                                                         java数据结构之HashMap

万事开头难,懒惰一段时间后,想写些东西,发现不知道从何下笔,那就先从HashMap开始。

这是很早之前梳理java数据结构画得一张图,从这里我们可以看到,java collection主要包括Map和Collection两个接口,这里先说下Map这个接口。

An object that maps keys to values.  A map cannot contain duplicate keys;each key can map to at most one value.

这是Map接口的简介,简单说Map就是一中key-value的数据结构,Map不能包含重复的key,每个key只能对应一个value。

看下Map接口的方法,一目了然,基本根据方法名称就可以看出这个方法表示什么。

Map的下一层就是AbstractMap,关于AbstractMap这个类的介绍如下

 This class provides a skeletal implementation of the <tt>Map</tt> interface, to minimize the effort required to implement this interface.

AbstractMap类实现了Map接口的一些公共方法,以便将实现此接口所需的工作最小化。

AbstractMap类中实现的公共方法包括containsValue containsKey、get(Object key)、remove(Object key)等等,当然这些方法里面的部分实现也依赖于子类的某些方法。这种模式也叫做骨架模式,父抽象类制定了方法的部分骨架,具体实现由子类实现,这样多个子类可以有不同的实现。接下来看下HashMap类的细节。

HashMap其实就是一种数组链表的数据结构,数组是说不同hash的key放在一个entry[]数组里面,链表是指当key的hash相同时,HashMap采用的是链表法来处理hash冲突。这样HashMap就结合了数组和链表的优点。HashMap运行key、value为null。

上图就是HashMap的数据结构,每一个bucket都有一个entry。

    /**
     * Constructs an empty <tt>HashMap</tt> with the specified initial
     * capacity and load factor.
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    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();
    }

看下构造方法, initialCapacity 表示初始容量, loadFactor表示加载因子,默认initialCapacity 为16, float loadFactor为0.75,当HashMap的实际长度超过initialCapacity*loadFactor时,为了避免过多的hash碰撞,HashMap就会进行扩容。代码如下

  /**
     * Adds a new entry with the specified key, value and hash code to
     * the specified bucket.  It is the responsibility of this
     * method to resize the table if appropriate.
     *
     * Subclass overrides this to alter the behavior of put method.
     */
    void addEntry(int hash, K key, V value, int 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);
    }

那么HashMap是怎样确定某个key应该放在哪个位置,其实是根据对key进行hash后,再对Entry<K,V>[] table长度取余。

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

当key的hash冲突时,采用链头插入法将新的entry加入到hashMap,这样做是为了避免尾部遍历。

HashMap就暂时介绍到这里,当然HashMap存在并发问题,HashMap并不是一个线程安全的类,可以使用Collections.synchronizedMap(Map<K,V> m)使得HashMap变为线程安全,或者使用juc包的ConcurrentHashMap类,这个更高效,关于hashmap的线程安全问题见下文链接,写的比较详细。

http://www.cnblogs.com/andy-zhou/p/5402984.html

猜你喜欢

转载自blog.csdn.net/nongfuyumin/article/details/88538861