Java基础之:集合——Map——HashMap

Java基础之:集合——Map——HashMap

HashMap简单介绍

  1. Map接口的常用实现类:HashMap、Hashtable和Properties。

  2. HashMap是 Map 接口使用频率最高的实现类。

  3. HashMap 是以 key-val 对的方式来存储数据 [案例 Entry ]

  4. key 不能重复,但是是值可以重复,允许使用null键和null值。

  5. 如果添加相同的key , 则会覆盖原来的key-val ,等同于修改.(key不会替换,val会替换)

  6. 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.

  7. HashMap没有实现同步,因此是线程不安全的,文档 The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.)

关于HashMap的案例,就是上一篇博客中描述Map的案例。使用的是HashMap。

HashMap底层机制

(k,v)是一个Node节点,实现了Map.Entry<K,V>。

jdk7.0的hashmap 底层实现[数组+链表], jdk8.0 底层[数组+ 链表/红黑树]

这里的链表都只有next属性,没有prev属性,即单向链表。

扩容机制

table表的扩容机制(即上图中第一行类似数组的表):

  1. HashMap底层维护了Node类型的数组table,默认为null

  2. 当创建对象时,将加载因子(loadfactor)初始化为0.75

  3. 当添加元素时(调用putVal方法),需要通过该元素的哈希值获取在table中的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,需要继续判断是否相等,如果相等则直接覆盖,如果不相等则需要判断此时是树结构还是链表结构,做相应处理。如果添加时发现容量不够就需要扩容。

  4. 如果第一次添加,则需扩容table容量为16,临界值(threshold)为12.(16 * 0.75 = 12)

  5. 即当table表的内容增长到临界值(threshold)时,就会自动扩容。(添加第13个元素进入table表时,扩容)

  6. 如果其他次添加则需扩容table容量到原来的2倍,临界值也改为原来的两倍。(例:第2次扩容,table -> 32 , threshold -> 24)

table表中单个索引位置的扩容机制(链表/红黑树):

  1. 在table表中,一开始默认是长度为16的数组

  2. 当某一个索引中的元素超过了8时,它优先会选择将长度扩容2倍(即长度为32)的数组。

  3. 它会认为是不是由于数组的长度不够才导致一个索引中元素过多。

  4. 但当它发现长度为32时,某一个索引中的元素还是超过9时,它还是会优先选择将长度再次扩容到2倍(即长度为64)的数组。

  5. 在长度为64的数组中,它发现某一个索引中的元素还是超过10时,它就会对该索引所在的链表转化为红黑二叉树.

  6. 所以在第十一个元素时,才会对该索引所在的链表转化为红黑二叉树.

测试代码

import java.util.HashMap;
public class HashMapTreeNode {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) {
​
        HashMap map = new HashMap();
​
        for (int i = 1; i <= 20; i++) {
            User user = new User();
​
            map.put(user, user);
​
            System.out.println("i =" + i);
        }
    }
}
​
class User {
​
    // 保证每个元素放入同一个索引,将hashcode设置为1
    @Override
    public int hashCode() {
        return 1;
    }
​
    // 保证在同一个索引中,每个元素不会因为相同被覆盖,将equles设置为false
    @Override
    public boolean equals(Object obj) {
        return false;
    }
}

LinkedHashMap

LinkedHashMap继承自HashMap,包含了HashMap的所有机制,但不同的是LinkedHashMap是有序的(即添加和取出顺序相同).

简单案例:

package class_HashMap;
​
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
​
public class ClassTest01_LinkedHashMap {
​
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void main(String[] args) {
​
        HashMap map = new LinkedHashMap();

        map.put("1", "hello01");
        map.put("2", "hello02");
        map.put("3", "hello03");
        map.put("3", "hello05");
        map.put("4", "hello02");
        map.put(null, "hello02");
        map.put("5", null);

        //遍历键值对
        Set entrySet = map.entrySet();
        Iterator iterator = entrySet.iterator();
        while(iterator.hasNext()) {
            Object obj = iterator.next();
            Map.Entry node = (Map.Entry)obj;
            System.out.println(node.getKey() + " = " + node.getValue());
        }
        iterator = entrySet.iterator();
    }
​
}

程序输出:

1 = hello01

2 = hello02

3 = hello05

4 = hello02

null = hello02

5 = null

(0)

相关推荐