Map 接口
Map 接口介绍
- Map 和 Collection 并列,用于保存具有映射关系的数据:Key - Value
- Map 中的 key 和 value 可以是任何的引用类型数据,会封装到 HashMap$Node 对象中
- Map 中的 key 不允许重复,同 HashSet 一样
- Map 的 value 可以重复
- Map 的 key 可以为null,value 也可以为 null,key 为null 只能有一个,value 为 null 可以有多个
- 常用 String 类作为 Map 的 key
- key 和 value 存在单向一对一关系,即通过指定的 key 中能找到对应的 value
- Map 存放数据的 key - value 示意图,一对 k - v 是放在一个 HashMap$Node 中的,又因为 Node 是实现了 Entry 接口,有些书上也说,一对 k - v 就是一个 Entry
- 为了方便遍历,还会创建 EntrySet 集合
transient Set<Map.Entry<K,V>> entrySet;
Map 接口常用方法
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
Set<Map.Entry<K,V>> entrySet()
//Returns a Set view of the mappings contained in this map.
boolean equals(Object o)
V get(Object key)
boolean isEmpty()
Set<K> keySet()
V put(K key, V value)
void putAll(Map<? extends K,? extends V> m)
V remove(Object key)
default V replace(K key, V value)
default boolean replace(K key, V oldValue, V newValue)
default void replaceAll(BiFunction<? super K,? super V,? extends V> function)
int size()
Collection<V> values()
Map 的 遍历
//第一组: 先取出 所有的 Key , 通过 Key 取出对应的 Value
Set keyset = map.keySet();
System.out.println("-----第一种方式-----");
// 增强For
for (Object key : keyset) {
System.out.println(key + "-" + map.get(key));
}
System.out.println("-----第二种方式-----");
// 迭代器
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + map.get(key));
}
// 第二组 通过EntrySet 来获取k-v
Set entrySet = map.entrySet();
// (1) 增强For
System.out.println("-----使用EntrySet的增强For-----");
for (Object entry : entrySet) {
Map.Entry m = (Map.Entry) entry;
System.out.println(entry.toString()); // key = value // HashMap toString()
}
// (2) 迭代器
System.out.println("-----使用EntrySet的迭代器------");
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Object entry = iterator2.next();
System.out.println(entry);
}
// 第三组,取出所有的Value
Collection values = map.values();
// 可以使用Collection 的所有遍历方法
// (1) 增强For
for (Object value :values) {
System.out.println(value);
}
// (2) 迭代器
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object value = iterator1.next();
System.out.println(value);
}
Map 接口的实现类 —— HashMap
-
Map 接口的常用实现类:HashMap、Hashtable 和 Properties
-
HashMap 是 Map 接口使用频率最高的实现类
-
HashMap 是以 key - value 的方式存储数据(HashMap$Node)
-
key 不能重复,但是值可以重复,允许使用 null 键和 null值
-
如果添加相同的key,则会覆盖原来的 key - value ,等同于修改(key不会替换,value 被替换)
-
与 HashSet 一样,不保证映射的顺序,因为底层是以 hash 表的方式来存储的(JDK 8 的 HashMap 底层:数组 + 链表 + 红黑树)
-
HashMap 没有实现同步,因此线程不安全,方法没有做同步互斥的操作
扩容机制 同 HashSet 一样
Map 接口实现类 —— Hashtable
- 存放的元素是键值对,即 key - value
- Hashtable 的 key 和 value 都不能为 null,否则会抛出 NullPointerException
- Hashtable 使用的方法基本和 HashMap 一样
- Hashtable 是线程安全的
Hashtable 和 HashMap 的对比
版本 | 线程安全(同步) | 效率 | 是否允许null键值 | |
---|---|---|---|---|
HashMap | 1.2 | 不安全 | 高 | 可以 |
Hashtable | 1.0 | 安全 | 较低 | 不可以 |
Map 接口实现类 —— Properties
- Properties 类继承 Hashtable 类,使用特点和 Hashtable 类似
- Properties 可以用于从 xxx.properties 文件中,加载数据到 Properties 类对象,并进行读取和修改
- xxx.properties 文件通常作为配置文件
Map 接口实现类 —— TreeMap
- TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序
- 可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序
- reeMap实现了红黑树的结构
TreeMap的特点
- 不允许出现重复的key
- 可以插入null键,null值
- 可以对元素进行排序
- 无序集合(插入和遍历顺序不一致)
如何选择集合实现类
在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择,分析如下:
-
先判断存储的类型 (一组对象【单列】 或 一组键值对【双列】)
-
一组对象:Collection 接口
- 允许重复:List
- 增删多:LinkedList (底层维护了一个双向链表)
- 改查多:ArrayList (底层维护Object类型的可变数组)
- 不允许重复:Set
- 无序:HashSet (底层是HashMap,底层维护了一个哈希表【数组 + 链表 + 红黑树】)
- 排序:TreeSet (底层是 红黑树)
- 插入和取出顺序一致:LinkedHashSet( HashMap + 双向链表)
- 允许重复:List
-
一组键值对:Map
- 键无需:HashMap(底层是:哈希表 jdk7:数组 + 链表,jdk8:数组 + 链表 + 红黑树)
- 键排序:TreeMap (底层是红黑树)
- 键的插入和取出顺序一致:LinkedHashMap (HashMap + 双向链表)
- 读取文件:Properties