基本概念
- java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,其中类型参数如下:
K(Key) - 此映射所维护的键(Key)的类型,相当于目录
V(Value) - 映射值(Value)的类型,相当于内容 - Map集合是面向查询优化的数据结构, 在大数据量情况下有着优良的查询性能,经常用于根据key检索value的业务场景
- 该集合中key是不允许重复的,而且一个key只能对应一个value
- 该集合的主要实现类有:HashMap类、TreeMap类、LinkedHashMap类、Hashtable类、Properties类
- 其中HashMap类的底层是采用哈希表进行数据管理的。
- 其中TreeMap类的底层是采用红黑树进行数据管理的。
- 其中LinkedHashMap类与HashMap类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
- 其中Hashtable类是古老的Map实现类,与HashMap类相比属于线程安全的类,且不允许null作 为key或者value的数值
- 其中Properties类是Hashtable类的子类,该对象用于处理属性文件,key和value都是String类型的
笔试题中可能考HashMap和Hashtable的区别,只要答出Hashtable是线程安全的,效率较低,且不允许null作为key或value的数值即可
哈希表的结构
哈希表这样key-value 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值,所有查找的时间复杂度为O(1),加快了查找速度
哈希表存在的问题:哈希碰撞
我只们知道哈希表中哈希值是这样得到的:hashfunction(Key值) = 哈希值
那么不同的输入得到了同一个哈希值,就发生了哈希碰撞
解决哈希碰撞的方法
-
开放定址法
如果遇到哈希冲突,找hash表剩下空余的空间,找到空余的空间然后插入。即哈希表中对应哈希值已有元素,就对应下一个元素
-
链地址法(拉链法)
如果遇到冲突,他就会在原地址新建一个空间,然后以链表结点的形式插入到该空间
简单来说就是发生碰撞时,在该位置加一个链表
HashMap是一个通过拉链法解决哈希冲突的哈希表
Map集合实现元素的增加和修改
注意哈希表中是没有先后放入次序的
//1.准备一个Map集合并打印
Map<String,String> m1 = new HashMap<>();
//自动调用HsahMap中的toString方法,默认打印格式为:{key1=value1, key2=value2, ...}
System.out.println("m1="+m1);//{}
System.out.println("-----------------");
//2向集合中添加元素并打印
String str1 = m1.put("1","one");
System.out.println("原来的value数值为:"+str1);//null
System.out.println("m1="+m1);//{1=one}
str1 = m1.put("2","two");
System.out.println("原来的value数值为:"+str1);//null
System.out.println("m1="+m1);//{1=one,2=two}
str1 = m1.put("3","three");
System.out.println("原来的value数值为:"+str1);//null
System.out.println("m1="+m1);//{1=one,2=two,3=three}
str1 = m1.put("1","eleven");
System.out.println("原来的value数值为:"+str1);//one 实现了修改的功能
System.out.println("m1="+m1);//{1=eleven,2=two,3=three}
元素放入HashMap的过程
在Map中用Key调用hashCode()得到哈希码值,哈希码值调用哈希算法得到哈希值
哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值。addr=f(key)
元素放入的过程如下:
- 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置。
- 若该位置没有元素,则将该键值对直接放入即可
- 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入
- 若key与已有元素的哈希值相同,则使用key调用equals方法与已有元素依次比较
- 若相等则将对应的value修改,否则将键值对直接放入即可
Map集合实现元素查找和删除
//实现集合中元素的查找操作
boolean b1 = m1.containsKey("11");
System.out.println("b1="+b1);//false
b1 = m1.containsKey("1");
System.out.println("b1="+b1);//true
b1 = m1.containsValue("one");
System.out.println("b1="+b1);//false
b1 = m1.containsValue("eleven");
System.out.println("b1="+b1);//true
String str2 = m1.get("5");
System.out.println("str2="+str2);//null
str2 = m1.get("3");
System.out.println("str2="+str2);//three
实现集合中元素的删除操作
System.out.println("-----------------");
str2 = m1.remove("1");
System.out.println("被删除的Value是"+str2);//eleven
System.out.println("m1="+m1);
Map集合的三种遍历方式
1.获取Map集合中所有的Key并组成Set视图
// 获取Map集合中所有的Key并组成Set视图
Set<String> s1 = m1.keySet();
//遍历所有的Key
for(String ts : s1){
System.out.println(ts+m1.get(ts));
}
2.获取Map集合中所有的Value并组成Collection视图
// 获取Map集合中所有的Value并组成Collection视图
Collection<String> c1 = m1.values();
for(String ts : c1){
System.out.println(ts);
}
3.获取Map集合中所有的键值对并组成Set视图
System.out.println("-----------------");
// 获取Map集合中所有的键值对并组成Set视图
Set<Map.Entry<String, String>> entries = m1.entrySet();
for(Map.Entry<String, String> me : entries){
System.out.println(me);
}