Map集合及HashMap源码分析

来源:互联网 发布:华为端口聚合配置 编辑:程序博客网 时间:2024/06/13 09:11

Map主要学习HashMap,TreeMap,HashTable

HashMap

因为HashMap是基于hash表实现的,所以不会hash数据结构的可以参考如下链接,hashMap是采用的链地址法来解决冲突

点击打开链接

以下面一段代码来分析hashMap源码

public void Test(){HashMap<String,String> hashMap = new HashMap<String, String>();hashMap.put("1", "m");hashMap.put("2", "a");hashMap.put("3", "p");System.out.println(hashMap.get("1"));}

构造函数:

 public HashMap(int initialCapacity, float loadFactor) {     //检测参数,loadFactor表示装载因子,因为HashMap采用的链地址法,所以装载因子可以是1,     // 但是会影响性能,默认选择为0.75        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;        //该map中装载的最大数量        threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);        //创建数组        table = new Entry[capacity];        useAltHashing = sun.misc.VM.isBooted() &&                (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);        init();    }

put(K key, V value)

首先查找map中有没该元素,如果有,则直接替换其值,如果没有找到,则通过addEntry(int hash, K key, V value, int bucketIndex)插入数据,把这个值插入到链表的头部

public V put(K key, V value) {        if (key == null)//插入key为null的值            return putForNullKey(value);        int hash = hash(key);//获得hash值        int i = indexFor(hash, table.length);//获得在table中的索引        //迭代查找该元素在链表中要插入的位置        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            //如果该map中已经有该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;    }


get(Object key)

public V get(Object key) {        if (key == null)            return getForNullKey();        //通过getEntry来查找        Entry<K,V> entry = getEntry(key);        return null == entry ? null : entry.getValue();    }

final Entry<K,V> getEntry(Object key) {        int hash = (key == null) ? 0 : hash(key);//得到hash值        //遍历此节点位置的链表        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;    }

remove(Object 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) {  //获取hash值        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--;                if (prev == e)//表名删除的是链表的头                    table[i] = next;                else                    prev.next = next;                e.recordRemoval(this);                return e;            }            prev = e;            e = next;        }        return e;    }

与HashMap相对应的还有HashTable,HashMap和HashTable有什么区别

看一下HashTable源码:

public class Hashtable<K,V>    extends Dictionary<K,V>    implements Map<K,V>, Cloneable, java.io.Serializable

可以看到,HashTable和HashMap一样,都是实现Map来实现的

来看put方法:

/**     * Maps the specified <code>key</code> to the specified     * <code>value</code> in this hashtable. Neither the key nor the     * value can be <code>null</code>. <p>     *     * The value can be retrieved by calling the <code>get</code> method     * with a key that is equal to the original key.     *     * @param      key     the hashtable key     * @param      value   the value     * @return     the previous value of the specified key in this hashtable,     *             or <code>null</code> if it did not have one     * @exception  NullPointerException  if the key or value is     *               <code>null</code>     * @see     Object#equals(Object)     * @see     #get(Object)     */    public synchronized V put(K key, V value) {        // Make sure the value is not null        if (value == null) {            throw new NullPointerException();        }        // Makes sure the key is not already in the hashtable.        Entry tab[] = table;        int hash = hash(key);        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                V old = e.value;                e.value = value;                return old;            }        }        modCount++;        if (count >= threshold) {            // Rehash the table if the threshold is exceeded            rehash();            tab = table;            hash = hash(key);            index = (hash & 0x7FFFFFFF) % tab.length;        }        // Creates the new entry.        Entry<K,V> e = tab[index];        tab[index] = new Entry<>(hash, key, value, e);        count++;        return null;    }

从上面可以看到,增加了synchronized关键字,所以是线程安全的,还有注释说到,其key和value不能为空


所以HashMap和HashTable的区别如下:

1.HashTable是线程安全的,HashMap不是线程安全的

2.HashMap可以存储key和value为null的值,HashTable不能

3.还有一个区别HashMap的Iterator是fail-fast机制的,所以HashMap在迭代过程中,如果有集合有被修改,那么将会抛出ConcurrentModificationException异常,

而Hashtable的enumerator迭代器不是fail-fast.


TreeMap

TreeMap使用红黑树来实现,是一种有序的数据结构,因为总是处于一种平衡的状态,所以没有调优因子。


TreeMap和HashMap的区别

HashMap是hash表来实现,TreeMap使用红黑树来实现

TreeMap是有序的,HashMap是无序的


怎么选择使用HashMap还是TreeMap了

如果插入和更新都比较频繁的话,那么保证元素的有序可以提高快速和频繁查找的性能。如果对于排序操作(例如产生一个报表合作者运行一个批处理程序)的要求不是很频繁的话,那么把数据以无序的方式存储,然后在需要排序的时候用Collections.sort(…)来进行排序,会比用有序的方式来存储可能会更加高效


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 脚底起茧走路疼怎么办 脚底有茧走路疼怎么办 脚趾长茧子很疼怎么办 脚底的老茧很痛怎么办 脚底老皮严重厚怎么办 脚趾起茧走路疼怎么办 脚底厚厚的死皮怎么办 脚上老茧走路疼怎么办 脚底很厚的茧怎么办 长螨虫的脸应该怎么办 荞麦皮枕头生虫怎么办 车保养手册丢了怎么办 乳胶枕发黄掉渣怎么办 拉完头发太贴了怎么办 头发又厚又蓬松怎么办 手捻葫芦去皮后怎么办 苹果5s屏幕脱胶怎么办 夏天车内温度高怎么办 反复长粉刺痘痘怎么办 砂锅烫到手很痛怎么办 低压高怎么办吃什么好 熬夜多了掉头发怎么办 复蚕丝被洗过了怎么办 买了梅邦虫草精怎么办 医院不开转院证怎么办 棕垫一直有味道怎么办 棕子床垫味道大怎么办 羊绒大衣洗坏了怎么办 无痕内裤开胶了怎么办 衬衫洗了会缩水怎么办 脾虚引起的眼袋怎么办 沙漠玫瑰根烂了怎么办 多肉种子不发芽怎么办 多肉植物掉叶子怎么办 白色衣服染了蓝色怎么办 白色的衣服染色了怎么办 白毛衣染上金纺怎么办 白色的衣服变黄怎么办 白衣服84漂黄了怎么办 真丝的衣服皱了怎么办 衣服领子洗大了怎么办