Map in Java
I. Map
java.util.Map<K,V>:
- Map 是一个顶层的接口,不是 Collection 的子接口,用来存储键值对 (key - value)
- 将键 Key 映射到值的对象,一个映射不能包含重复的值,每个键最多只能映射到一个值
- K: 此映射所维护的键 key 的类型
- V: 映射值 value 的类型
- Map 中 key 不可重复, value 可以重复
II. Map 和 Collection 的区别
- Map
- 集合存储的元素是成对出现的,Map集合的键是唯一的,值是可以重复的
- Map 集合的数据结构只针对键 key 有效,跟值无关
- Collection
- 集合存储的元素是单独出现的
- Collection 的实现类 Set 的值是不可以重复的,List是可以重复的
- Collection 的数据结构是针对元素有效
III. Map 功能概述
- 添加功能
V put(K key, V value)
: 添加元素,存储时,如果key不存在,直接存储; 如果key存在,就把值替换成新值,返回旧值void putAll(Map<? extends K,? extends V> m)
: 添加一个map中所有的键值对
- 删除功能
void clear()
: 移除所有的键值对void remove(Object key)
: 根据键删除键值对,并返回键值对中的值
- 判断功能
boolean containsKey(Object key)
: 判断集合是否包含指定的键boolean containsValue(Object value)
: 判断集合是否包含指定的值boolean isEmpty()
: 判断集合是否为空
- 获取功能
Set<Map.Entry<K,V>> entrySet()
: 获得键值对的 set 集合Set<K> keySet()
:获取集合中所有键的 set 集合Collection<V> values()
: 获取集合中所有值的 collection 集合V get(Object key)
: 返回指定键所映射的值,根据键获取值
- 长度功能
int size()
: 返回集合中键值对的对数
IV. Map 的实现类
1. HashMap
java.util.HashMap<K,V>:
- 基于哈希表的 Map 接口的实现
- 此实现提供所有可选的映射操作,并允许使用 null 值和 null 键
- 此类不保证映射的顺序,特别是它不保证该顺序恒久不变,就是
无序
hashmap 构造方法
public HashMap()
:构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMappublic HashMap(Map<? extends K,? extends V> m)
:构造一个映射关系与指定 Map 相同的新 HashMap。所创建的 HashMap 具有默认加载因子 (0.75) 和足以容纳指定 Map 中映射关系的初始容量public HashMap(int initialCapacity)
:构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMappublic HashMap(int initialCapacity, float loadFactor)
:构造一个带指定初始容量和加载因子的空 HashMap
hashmap 示例
package org.lovian.collections.map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
// add key-value
System.out.println("put 1: " + map.put(1, "hello"));
System.out.println("put 1: " + map.put(1, "java"));
System.out.println("put 2: " + map.put(2, "world"));
System.out.println("put 3: " + map.put(3, "javaee"));
System.out.println("put 4: " + map.put(4, "c++"));
System.out.println("map: " + map);
// size
System.out.println("map size: " + map.size());
System.out.println("==============");
// remove
System.out.println("remove 4: " + map.remove(4));
System.out.println("remove 5: " + map.remove(5));
System.out.println("map: " + map);
System.out.println("==============");
// contains
System.out.println("contains3: " + map.containsKey(3));
System.out.println("contains4: " + map.containsKey(4));
System.out.println("contains java: " + map.containsValue("javaee"));
System.out.println("contains python: " + map.containsValue("python"));
System.out.println("==============");
// get
System.out.println("get 1: " + map.get(1));
System.out.println("get 5: " + map.get(5));
System.out.println("==============");
// keySet
Set<Integer> set = map.keySet();
System.out.println("set: " + set);
System.out.println("==============");
// values
Collection<String> col = map.values();
System.out.println("values: " + col);
System.out.println("==============");
// entryset
Set<Entry<Integer, String>> entrySet = map.entrySet();
System.out.println("entry set: " + entrySet);
// traverse map (by using entryset)
for (Entry<Integer, String> entry : entrySet) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println("key: " + key + " value: " + value);
}
System.out.println("==============");
map.clear();
System.out.println("map: " + map);
}
}
result
put 1: null
put 1: hello
put 2: null
put 3: null
put 4: null
map: {1=java, 2=world, 3=javaee, 4=c++}
map size: 4
==============
remove 4: c++
remove 5: null
map: {1=java, 2=world, 3=javaee}
==============
contains3: true
contains4: false
contains java: true
contains python: false
==============
get 1: java
get 5: null
==============
set: [1, 2, 3]
==============
values: [java, world, javaee]
==============
entry set: [1=java, 2=world, 3=javaee]
key: 1 value: java
key: 2 value: world
key: 3 value: javaee
==============
map: {}
遍历 map 有两种方式,一个是拿到 key 的 set, 通过 keySet 去找值; 另一种方式是拿到 key-value 的 entrySet集合,然后对 entrySet 去遍历 key 和 value
2. LinkedHashMap
java.util.LinkedHashMap<K,V>:
- Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序
- 哈希表保证唯一性:不重复
- 链表保证有序性: 有序 (存储和取出顺序一致)
3. TreeMap
java.util.TreeMap<K,V>:
- 基于红黑树(Red-Black tree)的 NavigableMap 实现
- 该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
- 基于红黑树,key可以排序,分自然排序和比较器排序,与 TreeSet 相同
- 元素保持唯一,不重复
V. 练习
1. 获取字符串中每一个字母出现的次数要求结果
Q: 有字符串 “aababcabcdabcde” , 要求结果为 “a(5)b(4)c(3)d(2)e(1)” 思路:
- 定义一个TreeMap集合,以字符作为 key, 出现的 count 作为 value
- 将字符串转化为字符数组,遍历字符数组,然后将字符出现的次数存储到对应的 count 中
- 定义 stringbuffer 变量
- 遍历map集合,得到key value,进行字符串拼接
- 将stringbuffer 转换成 string 进行输出
为什么这里要选用 treemap, 原因是因为排序的字符是有顺序的, (自然顺序排序), 所以这里要用treemap集合对键进行自然排序
2. Hashtable 和 HashMap 的区别
Hashtable
java.util.Hashtable<K,V>:
- 注意
Hashtable
这里 t 是小写 - 此类实现一个哈希表,用来存储 key - value, null 不可作为键值
Hashtable 用法和 HashMap 基本相同,实际上 HashMap 就是用来代替 Hashtable 的
区别
- Hashtable
- 线程安全,效率低
- 不允许 null 键, null 值, null 会抛出 NullPointerException 异常
- HashMao
- 线程不安全,效率高
- 允许 null 键和 null 值
VI. 集合的嵌套
Map 集合可以作为 Map 集合的 value 从而进行嵌套。同样的,collection 集合也可以作为 map 集合的 value 进行嵌套
Share this on