关键词:
目录
2.2.1 Arraylist 与 LinkedList 异同
前言
前两期博客中我们一起去拜访了Java集合世界中的List集合和Set集合,今天我们一起去到Java集合世界的最后一站:Map集合。前面所说的List和Set集合都属于单列集合,只能存储一列数据;而Map集合是双列集合,它将数据以键值对形式存储,所以在形式上可存储两列数据。
1.Map集合
1.1 Map集合概述和特点
Map集合是双列集合,它将数据以键值对形式存储,所以在形式上可存储两列数据。Map是一个集合接口,不能直接创建对象,必须通过它的具体实现类(HashMap、TreeMap等)来创建Map对象。
interface Map<K,V> K:键的类型;V:值的类型
Map集合的特点
-
键值对映射关系
-
一个键对应一个值
-
键不能重复,值可以重复
-
元素存取无序
1.2 Map集合的基本功能
△ 方法介绍
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
△ 示例代码
public class MapDemo02
public static void main(String[] args)
//创建集合对象
Map<String,String> map = new HashMap<String,String>();
//V put(K key,V value):添加元素
map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
//V remove(Object key):根据键删除键值对元素
// System.out.println(map.remove("郭靖"));
// System.out.println(map.remove("郭襄"));
//void clear():移除所有的键值对元素
// map.clear();
//boolean containsKey(Object key):判断集合是否包含指定的键
// System.out.println(map.containsKey("郭靖"));
// System.out.println(map.containsKey("郭襄"));
//boolean isEmpty():判断集合是否为空
// System.out.println(map.isEmpty());
//int size():集合的长度,也就是集合中键值对的个数
System.out.println(map.size());
//输出集合对象
System.out.println(map);
1.3 Map集合的获取功能
△ 方法介绍
方法名 | 说明 |
---|---|
V get(Object key) | 根据键获取值 |
Set<K> keySet() | 获取所有键的集合 |
Collection<V> values() | 获取所有值的集合 |
Set<Map.Entry<K,V>> entrySet() | 获取所有键值对对象的集合 |
△ 示例代码
public class MapDemo03
public static void main(String[] args)
//创建集合对象
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
//V get(Object key):根据键获取值
// System.out.println(map.get("张无忌"));
// System.out.println(map.get("张三丰"));
//Set<K> keySet():获取所有键的集合
// Set<String> keySet = map.keySet();
// for(String key : keySet)
// System.out.println(key);
//
//Collection<V> values():获取所有值的集合
Collection<String> values = map.values();
for(String value : values)
System.out.println(value);
1.4 Map集合的遍历
第一种方式
-
遍历思路
-
我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
-
把所有的丈夫给集中起来
-
遍历丈夫的集合,获取到每一个丈夫
-
根据丈夫去找对应的妻子
-
-
-
步骤分析
-
获取所有键的集合。用keySet()方法实现
-
遍历键的集合,获取到每一个键。用增强for实现
-
根据键去找值。用get(Object key)方法实现
-
-
代码实现
public class MapDemo01
public static void main(String[] args)
//创建集合对象
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
//获取所有键的集合。用keySet()方法实现
Set<String> keySet = map.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
for (String key : keySet)
//根据键去找值。用get(Object key)方法实现
String value = map.get(key);
System.out.println(key + "," + value);
第二种方式
-
遍历思路
-
我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
-
获取所有结婚证的集合
-
遍历结婚证的集合,得到每一个结婚证
-
根据结婚证获取丈夫和妻子
-
-
-
步骤分析
-
获取所有键值对对象的集合
-
Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
-
-
遍历键值对对象的集合,得到每一个键值对对象
-
用增强for实现,得到每一个Map.Entry
-
-
根据键值对对象获取键和值
-
用getKey()得到键
-
用getValue()得到值
-
-
-
代码实现
public class MapDemo02
public static void main(String[] args)
//创建集合对象
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
//获取所有键值对对象的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry<String, String> me : entrySet)
//根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
1.5 Map集合案例——统计字符串中每个字符出现的次数
△ 案例需求
-
键盘录入一个字符串,要求统计字符串中每个字符串出现的次数。
-
举例:键盘录入“aababcabcdabcde” 在控制台输出:“a(5)b(4)c(3)d(2)e(1)”
△ 代码实现
public class HashMapDemo
public static void main(String[] args)
//键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
//创建HashMap集合,键是Character,值是Integer
// HashMap<Character, Integer> hm = new HashMap<Character, Integer>();
TreeMap<Character, Integer> hm = new TreeMap<Character, Integer>();
//遍历字符串,得到每一个字符
for (int i = 0; i < line.length(); i++)
char key = line.charAt(i);
//拿得到的每一个字符作为键到HashMap集合中去找对应的值,看其返回值
Integer value = hm.get(key);
if (value == null)
//如果返回值是null:说明该字符在HashMap集合中不存在,就把该字符作为键,1作为值存储
hm.put(key,1);
else
//如果返回值不是null:说明该字符在HashMap集合中存在,把该值加1,然后重新存储该字符和对应的值
value++;
hm.put(key,value);
//遍历HashMap集合,得到键和值,按照要求进行拼接
StringBuilder sb = new StringBuilder();
Set<Character> keySet = hm.keySet();
for(Character key : keySet)
Integer value = hm.get(key);
sb.append(key).append("(").append(value).append(")");
String result = sb.toString();
//输出结果
System.out.println(result);
2.集合补充知识以及常见面试题
2.1 Java集合框架图
上面这个图就是java整个集合体系框架图,对于初学者来说只需要掌握我标注出来的内容就差不多了,其他的作为了解内容。
2.2 各集合间的对比
2.2.1 Arraylist 与 LinkedList 异同
- 1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
- 2. 底层数据结构: Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向循环链表数据结构;
- 3. 插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行
add(E e)
方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element)
)时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。- 4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而ArrayList 实现了RandmoAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素对象(对应于
get(int index)
方法)。- 5. 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
2.2.2 ArrayList 与 Vector 区别
Vector 类的所有方法都是同步的。可以由两个线程安全地访问一个 Vector 对象、但是一个线程访问 Vector 的话代码要在同步操作上耗费大量的时间。
Arraylist 不是同步的,所以在不需要保证线程安全时时建议使用 Arraylist。
2.2.3 HashMap 和 Hashtable 的区别
- 线程是否安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过
synchronized
修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);- 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;
- 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。
- 初始容量大小和每次扩充容量大小的不同 : ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。
- 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
2.3 集合框架底层数据结构总结
Collection
1. List
- Arraylist: Object数组
- Vector: Object数组
- LinkedList: 双向循环链表
2. Set
- HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素
- LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
- TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树。)
Map
- HashMap: JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突).JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
- LinkedHashMap: LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
- HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
- TreeMap: 红黑树(自平衡的排序二叉树)
Java集合世界之旅到这就结束啦!各位小哥哥、小姐姐们,点个赞呀!
java中的集合框架大总结(代码片段)
直接上图: 从上面的集合框架图可以看到:Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合;另一种是图(Map),存储键/值对映射。Collection接口又有两个子接口,List和Set,再下面是一些... 查看详情
java基础之容器集合(collection和map)(代码片段)
目录前言一.Collection集合 1.1List集合1.1.1ArrayList集合1.1.2LinkedList集合1.2Set集合1.2.1HashSet集合HashSet集合保证元素唯一性源码分析:1.2.2TreeSet集合比较器排序Comparator的使用: 二.Map集合 2.1Map集合的概述与特点2.2Map集合的获... 查看详情
一篇文章让你精通:java集合讲解(六,map)(代码片段)
...经对前面List与Set有了一定的理解,下面我们就需要对集合中最后一个分类进行讲解Map,废话不多说,下面就让我们来看看Map有什么奇妙的地方吧!目录Map 分类HashMap:LinkHashMap(HashMap的子类):TreeMap:使用MapH... 查看详情
java示例代码_从集合Java(集合、数组、列表)获取子集合,并跟踪最后一个返回的集合
java示例代码_从集合Java(集合、数组、列表)获取子集合,并跟踪最后一个返回的集合 查看详情
java集合-map和queue的方法
从上面的集合框架图可以看到,Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection接口又有3种子类型,List、Set和Queue,再下面... 查看详情
死磕java集合之treemap源码分析
...号“彤哥读源码”,查看更多源码系列文章,与彤哥一起畅游源码的海洋。简介TreeMap使用红黑树存储元素,可以保证元素按key值的大小进行遍历。继承体系TreeMap实现了Map、SortedMap、NavigableMap、Cloneable、Serializable等接口。SortedMap规... 查看详情
groovymap集合(map集合定义|通过getclass函数获取map集合的类型|代码示例)(代码片段)
文章目录一、map集合定义二、获取map集合类型三、代码示例一、map集合定义声明键值对,其中键Key可以不使用引号,可以使用单引号‘’,也可以使用双引号“”;//创建键值对//键Key可以不使用引号,可以使用单引号'',也可以使... 查看详情
map集合。(代码片段)
Map集合:java.util,Map<k,v> 特点:1、键值对2、key-value一一对应3、key不允许重复。Map常用实现类:java.util.HashMap<k,v>集合 implementMan<k,v>接口。HashMap的特点:1、HashMap集合,底层是哈希表,查询速度快。 ... 查看详情
java中map集合的三种遍历方式(代码片段)
文章目录Map集合的遍历方式Map集合的遍历方式一:键找值Map集合的遍历方式二:键值对Map集合的遍历方式三:LambdaMap集合的遍历方式Map集合的遍历方式有3种:方式一:键找值的方式遍历:先获取Map集合全部的键,再根据遍... 查看详情
java集合学习笔记:map(代码片段)
Java集合学习笔记:MapUML简介源码阅读嵌套类interfaceEntry<K,V>静态方法comparingByKey()comparingByKey(Comparator<?superK>cmp)comparingByValue()comparingByValue(Comparator<?superV>cmp)比较器InterfaceCo 查看详情
java集合框架之map(代码片段)
...每个键最多只能映射一个值。Map接口提供了分别返回key值集合,value值集合以及(键值对)Entry 查看详情
java_集合知识点小结(代码片段)
一、java集合框架概述java集合可分为Collection和Map两种体系,其中: 1、Collection接口:单列数据,定义了存取一组对象的方法的集合;List:元素有序、可重复的集合Set:元素无序,不可重复的集合 2、Map接口:双列数据,... 查看详情
groovymap集合(map集合操作符重载|*.展开操作符|代码示例)(代码片段)
文章目录一、map集合"*."展开操作符二、代码示例一、map集合"*."展开操作符对map集合使用"*."展开操作符,会将map集合中的所有键值对都进行遍历,并且调用指定的方法;并且,将指定方法的调用返回结果输出到一个... 查看详情
java集合(list,set,map)详细总结(代码片段)
集合的由来: 数组是长度是固定的,当添加的元素超过数组的长度时需要对数组重新定义,太麻烦了,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少。数... 查看详情
容器集合(集合的进阶,collection,list,set,map,map集合的综合使用--斗地主案列,并发修改异常,列表迭代器,java面试中几个集合面试题)(代码片段)
目录集合的体系结构Collection集合:collection集合的常用方法:List集合:List集合特有的方法:ArrayList集合:LinkedList集合: Set集合:HashSet集合:HashSet保证元素唯一性源码分析:TreeSet集合:Map集合&... 查看详情
java集合之map(代码片段)
一、Map的实现类的结构Map:双列数据,存储key-value对的数据---类似于高中的函数:y=f(x)(JDK1.2才有)HashMap:(1.2才有)作为Map的主要实现类;线程不安全,效率高;存储null的key和valueLinkedHashMap:(1.4才有)保证在遍历map元素时,可以按... 查看详情
groovymap集合(根据key获取map集合中对应的值|map.key方式|map.‘key’方式|map[‘key’]方式|代码示例)(代码片段)
文章目录一、根据Key获取map集合中对应的值1、通过map.Key方式获取map集合中的值Value2、通过map.'Key'方式获取map集合中的值Value3、通过map['Key']方式获取map集合中的值Value二、完整代码示例一、根据Key获取map集合中对应的... 查看详情
java集合04_map接口概述常用方法排序hashtable面试题(代码片段)
....TreeMap排序⑥.Hashtable面试题①.Map接口的概述①.Map是双列集合与Collection的单列集合并列存在②.Map<K,V>这里的K、V都应该是引用数据类型③.HashSet底层依赖HashMap,单列底层依赖双列集合④.Map中的key可以为null,value 查看详情