Map 接口及实现类

发布时间 2023-07-06 18:03:43作者: 墨染启明

Map 接口

Map 接口介绍

image

image

image

  1. Map 和 Collection 并列,用于保存具有映射关系的数据:Key - Value
  2. Map 中的 key 和 value 可以是任何的引用类型数据,会封装到 HashMap$Node 对象中
  3. Map 中的 key 不允许重复,同 HashSet 一样
  4. Map 的 value 可以重复
  5. Map 的 key 可以为null,value 也可以为 null,key 为null 只能有一个,value 为 null 可以有多个
  6. 常用 String 类作为 Map 的 key
  7. key 和 value 存在单向一对一关系,即通过指定的 key 中能找到对应的 value
  8. Map 存放数据的 key - value 示意图,一对 k - v 是放在一个 HashMap$Node 中的,又因为 Node 是实现了 Entry 接口,有些书上也说,一对 k - v 就是一个 Entry
  9. 为了方便遍历,还会创建 EntrySet 集合 transient Set<Map.Entry<K,V>> entrySet;
image-20230706161832079

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

  1. Map 接口的常用实现类:HashMap、Hashtable 和 Properties

  2. HashMap 是 Map 接口使用频率最高的实现类

  3. HashMap 是以 key - value 的方式存储数据(HashMap$Node)

  4. key 不能重复,但是值可以重复,允许使用 null 键和 null值

  5. 如果添加相同的key,则会覆盖原来的 key - value ,等同于修改(key不会替换,value 被替换)

  6. 与 HashSet 一样,不保证映射的顺序,因为底层是以 hash 表的方式来存储的(JDK 8 的 HashMap 底层:数组 + 链表 + 红黑树)

  7. HashMap 没有实现同步,因此线程不安全,方法没有做同步互斥的操作

扩容机制 同 HashSet 一样

Map 接口实现类 —— Hashtable

  1. 存放的元素是键值对,即 key - value
  2. Hashtable 的 key 和 value 都不能为 null,否则会抛出 NullPointerException
  3. Hashtable 使用的方法基本和 HashMap 一样
  4. Hashtable 是线程安全的

Hashtable 和 HashMap 的对比

版本 线程安全(同步) 效率 是否允许null键值
HashMap 1.2 不安全 高 可以
Hashtable 1.0 安全 较低 不可以

Map 接口实现类 —— Properties

  1. Properties 类继承 Hashtable 类,使用特点和 Hashtable 类似
  2. Properties 可以用于从 xxx.properties 文件中,加载数据到 Properties 类对象,并进行读取和修改
  3. xxx.properties 文件通常作为配置文件

Map 接口实现类 —— TreeMap

  • TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序
  • 可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序
  • reeMap实现了红黑树的结构

TreeMap的特点

  • 不允许出现重复的key
  • 可以插入null键,null值
  • 可以对元素进行排序
  • 无序集合(插入和遍历顺序不一致)

如何选择集合实现类

在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择,分析如下:

  1. 先判断存储的类型 (一组对象【单列】 或 一组键值对【双列】)

  2. 一组对象:Collection 接口

    • 允许重复:List
      • 增删多:LinkedList (底层维护了一个双向链表)
      • 改查多:ArrayList (底层维护Object类型的可变数组)
    • 不允许重复:Set
      • 无序:HashSet (底层是HashMap,底层维护了一个哈希表【数组 + 链表 + 红黑树】)
      • 排序:TreeSet (底层是 红黑树)
      • 插入和取出顺序一致:LinkedHashSet( HashMap + 双向链表)
  3. 一组键值对:Map

    • 键无需:HashMap(底层是:哈希表 jdk7:数组 + 链表,jdk8:数组 + 链表 + 红黑树)
    • 键排序:TreeMap (底层是红黑树)
    • 键的插入和取出顺序一致:LinkedHashMap (HashMap + 双向链表)
    • 读取文件:Properties