- Map
- 提供的方法
- HaspMap
- 存储结构
- 插入及扩容
- HashMap和Hashtable
- HashMap的迭代方法
- 判等原则
- LinkedHashMap
Map
Map系:
每一个Map元素包括两个值,一个是key另一个是value,二者存在映射关系,也就是可以通过key索引得到唯一对应的value。所以Map中key不允许重复,key的相等与否通过equals()
方法确定,key和value都是任何引用类型的数据。
Map中的key在一起就组成了一个Set集合(无序、不重复),并且Map提供了keySet()方法,用于返回所有key组成的Set集合。
Map和Set有很多相似的地方,如果把Map中存储的Key-Value对称一个变量,并且value是key的附庸,key在哪里valuse就在哪里的话,Map和Set就没有什么区别了。而如果把所有的value放在一起来看,Map又像是一个List(可重复,key看作索引)。
提供的方法
方法 | 功能 |
void clear() | 清空Map |
booelan containsKey(Object key) | |
booelan containsValue(Object key) | |
Set entrySet() | 返回key-value对组成的Set集合; |
Object get(Object key) | 获取key对应的value,不存在则返回null |
boolean isEmpty() | |
Set keySet() | 返回所有key组成的Set集合 |
Object put(Object key, Object value) | 添加一对值,如果已有key相同的,覆盖 |
void putAll(Map m) | 将m中的全部kv对复制到本map中 |
Object remove(Objecct key) | 删除kv对,返回value,key不存在返回null |
int size() | |
Collection values() | 返回该map中所有value组成的Collection |
Map中包含一个内部类:Entry,封装了key-value对。有以下三个方法:
getKey(), getValue() 以及setValue()。
HaspMap
存储结构
HashMap内部数据结构:数组+单链表。
数组为了索引访问,单链表为了HashCode相等但是equals返回false的问题。(和HashSet很像)。
table[0] 指定用于存储key = null的键值对。
数组的容量一定是2n,即使在创建时传入的参数不是2nHashMap也会将其向上转换。
如下图:(图源)
插入及扩容
创建HashMap的默认大小是16。在向HashMap添加kv对时,和HashSet一样,hashCode决定下标。
数组中的每一个位置被称作一个桶,桶中除了存放key,value外,还有自己的哈希值以及一个链表Entry。同一个链表中存放哈希值和散列桶取模运算(就是hashCode%capacity)结果相同的 Entry。如果HashCode相同,equals返回false时,新来的元素会被放置到对应桶中并插在原元素之前,也就是说,这里的链表采用的是“头插法”。
HashMap的扩容有些特殊,一般容器是装满了才进行扩容,但HashMap不是。它有一个LOAD_FACTOR
就是装载因子(小于1)来限制HashMap的装载量(maxLoad = capacity * LOAD_FACTOR),也就是说它里面的元素个数是达不到最大容量的。具体原因参考了躺沙滩上等死的博文。
在需要扩容时默认扩容后是原来的2倍,然后将旧容器的所有键值对重新插入新容器。
HashMap和Hashtable
二者都是Map的实现类,区别主要是:
- Hashtable是一个**线程安全的Map实现,而HashMap是线程不安全的;所以HashMap性能会高一点。
- Hashtable不允许使用null作为key或value,但HashMap允许。
package com.klaus.maps;
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
System.out.println(map.put(1, "a")); // null
System.out.println(map.put(2, "b"));// null
System.out.println(map.put(1, "x"));// a
System.out.println(map);// {1=x, 2=b}
}
}
注释的内容是输出结果,正常添加是返回的都是null,而在添加失败时返回key已对应value。
HashMap的迭代方法
Map接口并没有获取Iterator的方法,并且Iterator只适用于Collection,所以说只能获取key的Set集合然后再调用iterator()方法获得迭代器。
//获取迭代器
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()){
System.out.println(map.get(iterator.next()));
}
判等原则
HashMap和Hashtable都是只根据equals()的返回结果来去确定
自定义类做key的时候,如果重写equals()和hashCode()方法,就应该保证equals()的结果和hashCode()的结果是一致的,即:equals()返回true时,hashCode()的值应该相等。
对比hashSet,判等不仅要求equals()返回true,还要hashCode()相等。
LinkedHashMap
这是HashMap的子类,与LinkedHashSet类似,它也是用双向链表维护Map。