一、Map集合的概述
1、概述:
Map接口是Java集合框架中的一种用于存储键值对映射关系的接口。interface Map<K,V> 其中K是键的类型,键是唯一的,不重复。V是值的类型,是可以重复。且每个键可以映射最多一个值。注意的是如果存在两个相同的键时,则会将现在的值替换之前的值。key 和 value 都可以是任何引用类型的数据。Map 的 key 不允许重复,value 可以重复,
- 即同一个 Map 对象的任何两个 key 通过 equals 方法比较总是返回 false。
Map 中的 key 和 value 之间存在单向一对一关系,即通过指定的 key,总能找到唯一的、确定的 value。从 Map 中取出数据时,只要给出指定的 key,就可以取出对应的 value。
Map 接口主要有两个实现类:HashMap 类和 TreeMap 类,这里先看HashMap类。
创建方式:以多态的形式创建对象。
Map<String, Integer> hashMap = new HashMap<>();
HashMap的继承实现结构图以及HashMap的构造方法:
2、特点:
- 键值对映射关系
- 一个键对应一个值
- 键不能重复,值可以重复
- 元素存取无序
- 允许空键值:Map中允许使用null 作为键和 值。
在此,我会列出Map集合中的一些常用方法,并对这些方法进行代码的实现
二、java.util.Map接口中的常用方法
1、Map集合以key和value的方式存储数据:键值对方式
-
key和value都是引用数据类型。
-
都是存储对象的内存地址
-
Interface Map<K,V>
-
-
参数类型
K
- 此映射维护的密钥类型V
- 映射值的类型
-
-
2、Map接口中常用的方法:
第一个方法:向Map集合中添加键值对
V put(K key, V value)
第二个方法:返回指定键映射到的值,通过key获取value ,若没有获取到则返回null
V get(Object key)
第三个方法:从此映射中删除所有映射(可选操作)。 清空Map集合
void clear()
第四个方法:判断Map是否包含某个key, 如果此映射包含指定键的映射,则返回true。
boolean containsKey(Object key)
参数 :key - 要测试其在此Map中是否存在
第五个方法:判断Map是否包含某个value
boolean containsValue(Object value)
第六个方法:判断Map中元素个数是否为0
boolean isEmpty()
获取Map集合中键值对的个数:
int size()
第七个方法:获取Map集合中所有的key(所有的键都是一个“Set集合”)
Set<K> keySet()
返回此映射中包含的键的Set视图。
第八个方法:通过key删除键值对
V remove(Object key)
如果存在,则从该映射中移除键的映射(可选操作)。
default boolean remove(Object key, Object value)
仅当指定键当前映射到指定值时,才删除该条目。
第十个方法:获取Map集合中所有的value,返回一个“Collection”
Collection<V> values()
第十一个方法:将Map集合转换成一个Set集合
Set<Map.Entry<K,V>> entrySet()
注意:【Map集合通过entrySet()方法转换成的这个Set集合,Set集合中的元素的类型是Map.Entry<K,V>】
【Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态内部类】
第十二个方法:返回指定键映射到的值,如果此映射不包含该键的映射,则返回 defaultValue。
default V getOrDefault(Object key, V defaultValue)
第十三个方法:仅当指定键当前映射到某个值时才替换该条目。
default V replace(K key, V value)
仅当指定键当前映射到指定值时,才删除该条目:
default boolean replace(K key, V oldValue, V newValue)
3、Map集合的常用方法代码实现:
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class test{
public static void main(String args[]) {
//创建Map集合
Map<Integer,String> myMap = new HashMap<>();
//向集合中添加键值对
myMap.put(2,"abc");
myMap.put(3,"张三");
myMap.put(4,"李四");
myMap.put(5,"老六");
//通过key获取value
String ss = myMap.get(5);
System.out.println(ss); //老六
System.out.println("获取键值对的数量:"+myMap.size());//获取键值对的数量:4
//通过key删除key-value
myMap.remove(2);
System.out.println(myMap.size()+"对"); //3对
//判断Map是否包含某个key
System.out.println(myMap.containsKey(2)); //false
//判断Map是否包含某个value
System.out.println(myMap.containsValue("张三")); //true
myMap.clear();
System.out.println("获取键值对的数量:"+myMap.size());//获取键值对的数量:0
System.out.println(myMap.isEmpty()); //true
//创建Map集合
Map<Integer,Integer> myMap2 = new HashMap<>();
//向集合中添加键值对
myMap2.put(2,9);
myMap2.put(3,8);
myMap2.put(4,4);
myMap2.put(5,2);
//获取所有的value
Collection<Integer> value = myMap2.values();
for (Integer i:value) {
System.out.println(i);/*9
8
4
2*/
}
}
}
三、HashMap存储数据的原理(put的流程)
JDK1.8 之后HashMap底层是数组 + 链表 + 红黑树。
HashMap 的存值过程:
(1) 根据 key 计算hash值。在put 的时候判断数组是否存在,如果不存在则用resize() 方法创建默认长度为16的数组。
(2) 确定要存入的 Node 在数组中的位置,根据 hash 值与数组最大索引进行按位与运算得到索引位置。
(3) 判断该位置是否有元素,如果没有直接创建一个 Node 存入。如果有元素,判断 key 是否相同,如果相同则覆盖,并且将原来的值直接返回。如果key 不相同,在原Node基础上添加新的Node,判断该位置是链表还是红黑树。
(4) 如果是红黑树,将 Node 存入红黑树。
(5) 如果是链表,遍历链表,找到最后一位,将 Node 存入。
(6) 将 Node 存入链表之后,判断链表的结构是否要调整,判断链表长度是否超过8,如果超过8,需要将链表转为红黑树,这里还有一个条件,如果数组的容量小于64,不转换红黑树,而是进行数组扩容,当数组的容量大于64的时候,再将链表转为红黑树。
(7)存完之后,再次判断数组是否进行扩容,根据负载因子来判断。
- 删除元素时,如果时以红黑树存储的如果节点小于 6 个将会变为链表存储
支持:🎁🎁🎁如果你觉得博主的文章的不错或者对你有帮助,可以点一个免费的关注支持一下博主,如果三连收藏支持就更好了吖,嘿嘿嘿,蟹蟹。