Map集合中HashMap
hashMap##
HashMap的特点
1.底层实现的是链表数组,JDK 8之后又加了红黑树;
2.实现了Map集合的全部方法
3.key值用 Set集合存放,所以key值是不允许重复,
4.允许空键和空值但空键只有一个。(且放在第一位)
5.元素是无序的,而且顺序会不定时改变(每次扩容后,都会重新哈希,也就是key通过哈希函数计算后会得出与之前不同的哈希值,这就导致哈希表里的元素是没有顺序,会随时变化的,这是因为哈希函数与桶数组容量有关,每次结点到了临界值后,就会自动扩容,扩容后桶数组容量都会乘二,而key不变,那么哈希值一定会变)
6.插入、获取的时间复杂度基本是 O(1)(前提是有适当的哈希函数,让元素分布在均匀的位置)
7.遍历整个 Map 需要的时间与数组的长度成正比(因此初始化时 HashMap 的容量不宜太大)
HashMap不是同步,所以HashMap线程不安全,但是效率高;HashTable是同步的,所以HashTable线程安全,但是效率低。
但HashTable已经弃用,如果需要线程安全,可以用synchronizedMap,例如 Map m = Collections.synchronizedMap(new HashMap(…));
遍历Map集合的方法
四种
1.通过keySet()方法遍历Map集合中的key值,`然后Map集合的对象获取value。
eg
map.get(key’)方法来获得value。
Map<String,String> map=new HashMap<String,String>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
for(String key:map.keySet()){
System.out.println("key:"+key);
System.out.println("value:"+map.get(key));
}
2.采用EntrySet()+Iterator进行遍历,EntrySet()返回的是一个Map.Entry的一个集合,它提供getKey(),getValue()方法来获取键值对。
Map<String,String> map=new HashMap<String,String>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
Iterator< Map.Entry<String,String>> it=map.EntrySet().iterator();
while(it.hasNext()){
Map.Entry<String,String> entry=it.next();
System.out.println("key:"+entry.getKey());
System.out.println("value:"+entry.getValue());
}
3.直接采用EntrySet+for增强进行遍历
Map<String,String> map=new HashMap<String,String>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
for(Map.Entry<String,String> entry:map.entrySet()){
System.out.println("key:"+entry.getKey());
System.out.println("value:"+entry.getValue());
}
4.取出Map集合中所有value的值,但是不能得到集合中的key值
Map<String,String> map=new HashMap<String,String>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
for(String value:map.values()){
System.out.println("value:"+value);
}
HashMap 的 4 个构造方法
//创建一个空的哈希表,初始容量为 16,加载因子为 0.75
- public HashMap()
//创建一个空的哈希表,指定容量,使用默认的加载因子
2. public HashMap(int initialCapacity)
//创建一个空的哈希表,指定容量和加载因子
3. public HashMap(int initialCapacity, float loadFactor)
//创建一个内容为参数 m 的内容的哈希表
public HashMap(Map<? extends K, ? extends V> m)
添加方法
//添加指定的键值对到 Map 中,如果已经存在,就替换
public V put(K key, V value)
添加时逻辑如下:
- 先调用 hash() 方法计算哈希值
- 然后调用 putVal() 方法中根据哈希值进行相关操作
- 如果当前 哈希表内容为空,新建一个哈希表
- 如果要插入的桶中没有元素,新建个节点并放进去
- 否则从桶中第一个元素开始查找哈希值对应位置
- 如果桶中第一个元素的哈希值和要添加的一样,替换,结束查找
- 如果第一个元素不一样,而且当前采用的还是 JDK 8 以后的树形节点,调用 putTreeVal() 进行插入
否则还是从传统的链表数组中查找、替换,结束查找
当这个桶内链表个数大于等于 8,就要调用 treeifyBin() 方法进行树形化
最后检查是否需要扩容
注:
*1. hash():计算对应的位置 resize(): - 扩容 putTreeVal():
- 树形节点的插入 treeifyBin():
- 树形化容器*