张小飞的Java之路——第三十七章——Map

文章详细介绍了Java中的Map接口,包括Map的基本概念、特点,如存储键值对、保证key的唯一性。重点讨论了HashMap的常用方法,如put、get、remove等,并解释了其数据结构(数组+链表,JDK8后引入红黑树)。此外,还提到了LinkedHashMap保证插入顺序的特点和TreeMap通过二叉树结构自动排序的功能,以及HashTable的特性和与HashMap的区别。
摘要由CSDN通过智能技术生成

写在前面:

视频是什么东西,有看文档精彩吗?

视频是什么东西,有看文档速度快吗?

视频是什么东西,有看文档效率高吗?


诸小亮:下面我们学习——Map

张小飞:这个我知道,Map——双列集合,也称映射、字典,没错吧

诸小亮:不错,那你可知道它存储什么样的数据?

张小飞:Map是用来存储**键值(key,value)**数据的

诸小亮:嗯嗯, 说的不错,Map 可以说是开发中最常使用的集合了,主要特点:

1. 一次存储一对儿数据,称为键值对
2. 能够保证key的唯一性

常用方法

诸小亮:既然你已经提前看过了,可否说一说?

张小飞:嗯,我试试吧

张小飞:首先 Map 其实是一个接口,更 Collection 类似,里面定义了很多共性的方法

诸小亮:那,都有哪些方法呢?

张小飞:这可不少,另外因为 Map 是个接口,所以用它的具体实现类 HashMap 演示

put

张小飞:put(key,value):添加元素,每次添加一对儿数据

public static void main(String[] args) throws Exception {
    //创建map对象,一般都声明泛型,限制存储的数据类型
    Map<String, String> map = new HashMap<>();
    //添加元素
    map.put("yase","zhenji");
    System.out.println(map);
}

结果:image.png

诸小亮:我记得 put 方法有返回值啊

张小飞:是的,返回的是指定key对应的值,比如:

public static void main(String[] args) throws Exception {
    Map<String, String> map = new HashMap<>();
    map.put("yase","zhenji");
    
    //因为map的key不能重复,所以新值覆盖老值,但是会返回老值
    String str = map.put("yase", "xishi");
    System.out.println(str);
}

结果:image.png

putAll

putAll(Map<k,v> map):把指定参数中的数据,都添加到当前 map 中
演示:省略

get

get(key):根据key获取value

image.png

containsKey

containsKey(key):是否包含指定的key,true:是,false:否

image.png

containsValue

containsValue(value):是否包含指定的value,true:是,false:否

image.png

isEmpty

isEmpty():判断是否空的,true:是,false:否

image.png

remove

remove(key):删除指定的key,返回对应的value

image.png

结果:image.png

clear

clear():清空整个map

image.png

结果:image.png

keySet()

keySet():把map中的所有key放到一个Set集合中返回,常用来遍历整个map

public static void main(String[] args) throws Exception {
    Map<String, String> map = new HashMap<>();
    map.put("yase","zhenji");
    map.put("lvbu","diaochan");
    map.put("lixin","xishi");
    
    //遍历整个map
    Set<String> keys = map.keySet();
    for(String key : keys) {
        System.out.println(map.get(key));
    }
}

结果:image.png

entrySet()

entrySet():返回包含映射关系的 Set 集合,也是常用的一种遍历方式

public static void main(String[] args) throws Exception {
    Map<String, String> map = new HashMap<>();
    map.put("yase","zhenji");
    map.put("lvbu","diaochan");
    map.put("lixin","xishi");
    
    // entrySet 返回Set集合,存储的是Map.Entry类型的对象
    // 一个Map.Entry就是map中的一对儿key,value
    Set<Map.Entry<String, String>> entries = map.entrySet();
    for(Map.Entry<String,String> en : entries){
        //一个 Map.Entry 中只包含一对key,value
        System.out.println(en.getKey()+"----"+en.getValue());
    }
}

结果:image.png

values

values():把map中的所有value放到一个集合中返回

image.png
结果:image.png

问题:为什么 values() 方法返回的不是 Set 集合?
答案:因为 map 中的 value 可能重复,而 Set 会自动去重

HashMap

诸小亮:我看你上面用的都是 HashMap 这个子类,对这个的挺多的啊

张小飞:还好吧,因为传说工作中 HashMap 使用的最频繁,所以一直用这个

诸小亮:嗯,你说的不错,工作中确实它使用的最多,那你能说说它的底层结构吗?

数据结构

张小飞:当然可以,数据结构是:可变数组 + 链表,其实 HashSet 内部的就是 HashMap

image.png
诸小亮:嗯,功课做的不错,继续说

张小飞:其数组,默认长16,当元素个数超过 数组大小 loadFactor 时,数组会扩容一倍

诸小亮:这个 _loadFactor 是?

张小飞:_loadFactor 是加载因子,默认值=0.75 ,表示当元素数量到 12 的时,数组扩容

诸小亮:那么,如何避免数组频繁的扩容呢?

张小飞:创建 HashMap 对象时,可以指定初始用量的大小,也就是可变数组的长度

诸小亮:然后呢?

张小飞: 一般建议,如果能提前确定需要存储的元素数量,在创建 HashMap 对象时候就要指定大小,避免
HashMap 频繁扩容,比如:

假如需要存储1200个元素,那么大小应该是:1200 / 0.75 = 1600;

因为是必须是2N次方,最终值应该是比1600大且最接近的2N次方的整数:2048

注意:其实在执行 new HashMap<>(1600); 时,其内部自动计算出2048,并设置为初始值

诸小亮:嗯,很不错,超乎我的意料

诸小亮:不过,JDK8 之后,HashMap底层做了优化啊

张小飞:是的,JDK8 之后,HashMap 的底层数据结构为:数组+链表+红黑树

  • 当数组的长度大于 64 且链表长度大于 8 时,链表会转换成红黑树结构

诸小亮:为什么在链表长度大于 8 的时候转换?

张小飞:有两点原因

1. 根据默认的算法,HashMap中链表的长度>8的概率是非常低的,小于千万分之一
	设置为 8 的原因是:不希望把链表转换为红黑树

2. 链表长度大于 8 后平均查询效率没有红黑树高

无序

诸小亮:什么是无序?

张小飞:就是,在 put 数据时,key的存放无法保证顺序,比如:

public static void main(String[] args) throws Exception {
    HashMap<String, String> map = new HashMap<>(1200);
    map.put("daji","女仆咖啡");
    map.put("yase","心灵战士");
    for(Map.Entry<String,String> en : map.entrySet()){
        //一个 Map.Entry 中只包含一对key,value
        System.out.println(en.getKey()+"----"+en.getValue());
    }
}

结果:image.png,取出的顺序,跟存放的顺序不同

空key 和 空value

张小飞:Map中,允许 null 作为key,null 作为 value,比如:

public static void main(String[] args) throws Exception {
    Map<String, String> map = new HashMap<>();
    
    map.put(null,"xishi");//key可以是null
    System.out.println(map.get(null));
    
    map.put("yase",null);//value也可以是null
    System.out.println(map.get("yase"));
}

结果:image.png

LinkedHashMap

诸小亮:说一说 LinkedHashMap 吧

张小飞:LinkedHashMap——是 HashMap 的子类,它最大的特点

  • 可以保证 key 存放时候的顺序
public static void main(String[] args) throws Exception {
    Map<String, String> map = new LinkedHashMap<>();
    map.put("yase","zhenji");
    map.put("lvbu","diaochan");
    map.put("lixin","xishi");
    Set<Map.Entry<String, String>> entries = map.entrySet();
    for(Map.Entry<String,String> en : entries){
        System.out.println(en.getKey()+"----"+en.getValue());
    }
}

结果:image.png,按照存放的顺序取出key,value

诸小亮:为什么它可以保证顺序呢?

张小飞:原理跟 LinkedHashSet 一样

TreeMap

诸小亮:我记得,还有一个 TreeMap 吧

张小飞:是的,TreeMap——是 Map 的具体子类
数据结构:

  • 二叉树结构,其实 TreeSet 内部的就是 TreeMap
  • 内部自动对 key 进行排序,比如:
public static void main(String[] args) throws Exception {
    Map<String, String> map = new TreeMap<>();//注意,这里是无参数的构造方法

    //这时候存储的key,必须实现Comparable接口
    map.put("yase","zhenji");
    map.put("lvbu","diaochan");
    map.put("lixin","xishi");
    map.put("anqila","xiaohongnv");
    System.out.println(map);
}

结果:image.png

张小飞:另外,TreeMap还有一个构造方法:TreeMap(Comparator<? super K> comparator);

  • 使用它创建对象时,需要提供一个 Comparator 比较器

HashTable

张小飞:还有一个HashTable——也是map的具体子类

诸小亮:它更 HashMap 有什么区别?

张小飞:HashMap就是为替代它而生,主要区别:

1. Hashtable 是不允许键或值为 nullHashMap 的键值都可以为 null
2. HashTable 都是同步方法
3. HashMap 的初始容量为:16Hashtable 初始容量为:11
4. HashMap 扩容规则为当前容量翻倍,Hashtable 扩容规则为当前容量翻倍 +1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值