一、Map接口:
map接口,是一种键值对的式的结构,开发中,经常使用这种结构
key:键,是唯一的,不能重复,若重复,则会覆盖原有key中的值(哈希表中是唯一的,不能 重复),所以用哈希表去维护,map之所以用hashmap的原因是要保证key的唯一性
value : 值 可以重复
注意:Map接口没有继承Collection
1. 常见方法:
map是接口,不能实例化,所以得用它的子类
在java中,Map的key可以是任意类型(泛型)
1)添加
V put(K key, V value);
当key重复时,不会创建多个键值对,只会进行覆盖
在HashMap中,可以使用null作为key
2)获取
V get(Object key);
如果获取的key不存在,则返回空
import java.util.Map;
@Test
void testMap01() {
Map<String, Integer> mps = new HashMap<>();
mps.put("name", 123);
mps.put("age", 23);
mps.put("gender", 56);
// 当key重复时,不会创建多个键值对,只会进行覆盖
mps.put("gender", 100);
System.out.println(mps);
System.err.println(mps.size());
System.err.println(mps.get("name"));
// 如果获取的key不存在,则返回空
System.err.println(mps.get("nickname"));
// 在HashMap中,以null作为key,可以不?
// 在HashMap中,可以使用null作为key
mps.put(null, 123);
System.out.println(mps);
System.out.println(mps.get(null));
}
3)getOrDefault、containsKey、remove、replace
@Test
void testMap02() {
Map<String, String> mps = new HashMap<>();
mps.put("name", "小豪");
mps.put("age", "13");
mps.put("gender", "男");
// 获取时,如果存在,则返回,如果不存在,则给定一个默认值
System.out.println(mps.getOrDefault("name2", "佚名"));
//是否包含某个键
System.out.println(mps.containsKey("name"));
System.out.println(mps.containsKey("nickname"));
// 根据key 移除整个键值对
System.out.println(mps.remove("name"));
System.out.println(mps);
// 根据key和value,移除整个键值对,键和值都匹配才会移除
System.out.println(mps.remove("age", "20"));
System.out.println(mps);
System.out.println(mps.remove("age", "13"));
System.out.println(mps);
// 注意,仅仅是替换key对应的值,如果没有,不会添加
mps.replace("gender", "male");
System.out.println(mps);
mps.replace("gender1", "male");
System.out.println(mps);
}
2. 遍历map结构
@Test
void testMap03() {
Map<String, Object> mps = new HashMap<>();
mps.put("name", "小豪");
mps.put("age", 13);
mps.put("gender", "男");
mps.put("address", "汉中");
}
1). keySet()
// 注意:这个方法错误,每当调一次next()就会向前走一次
// Set<String> keySet = mps.keySet();
// Iterator<String> keys = keySet.iterator();
// while (keys.hasNext()) {
// System.out.println(keys.next() +"---->"+ mps.get(keys.next()));
// }
//用这种方法进行迭代(迭代器)
// keySet(),将map的key 做成set,再迭代数据
Set<String> keySet = mps.keySet();//key是字符串,返回的set的类型是字符串类型
Iterator<String> keys = keySet.iterator();
while (keys.hasNext()) {
String key = keys.next();
System.out.println(key +"---->"+ mps.get(key));
}
//使用for循环加强简化迭代器
for (String key : mps.keySet()) {
System.out.println(key +"---->"+ mps.get(key));
}
2).entrySet()
//Entry返回的是map中的每一个键值对,返回的是set类型
Set<Entry<String,Object>> entrySet = mps.entrySet();
//迭代器
Iterator<Entry<String, Object>> iterator = entrySet.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
// while(iterator.hasNext()) {
// Entry<String, Object> set = iterator.next();
// System.out.println(set);
// }
//for循环加强
for (Entry<String, Object> entry : entrySet) {
System.out.println(entry.getKey() +"---->"+ entry.getValue());
}
3).forEach()
// 使用lambda表达式,简化遍历操作
entrySet.forEach(t -> System.out.println(t.getKey() +"---->"+ t.getValue()));
//之前提到的forEach的写法都可以用
4).jdk8提供的新的map自身的一种遍历方式
mps.forEach((k, v) -> System.out.println(k +"---->"+ v));
二、Map的常见实现子类:
HashMap
Hashtable
ConcurrentHashMap
1. 三者区别和联系:
HashMap 非线程安全 jdk1.2诞生
Hashtable(同步锁)线程安全 jdk1.0诞生
这个规则类似于线性表中的ArrayList和Vector
ArrayList 非线程安全 jdk1.2诞生
Vector(同步锁)线程安全 jdk1.0诞生
ConcurrentHashMap(Hashtable可以解决高并发,但随着技术的发展,用 ConcurrentHashMap) jdk1.5诞生 对HashMap进行改造,在HashMap中分段锁的机制
HashMap 默认由大小为16的数组组成,ConcurrentHashMap对每个节点进行加锁操作,相 当于加了16个分段锁,使得线程安全,但是效率比Hashtable至少高16倍。jdk8之后进行优化,做了自旋锁,本质不是锁,所以效率更高。
2. HashMap简介:
它是一个标准的哈希表
JDK8之前,HashMap:整体结构是一个"数组 + 链表" 结构
JDK8之后,HashMap:整体结构是一个"数组 + 链表 + 红黑树" 结
1)、哈希冲突:
(1).什么是哈希冲突
哈希冲突是指哈希函数算出来的地址被别的元素占用了。
(2).哈希冲突的四种解决方案:
1、再哈希法
2、开放定址法
3、链地址法
4、建立公共溢出区: