第十二章 Map(1.3)

Map

key得值;
JDK中在java.util包下提供了一组类库,用以实现集合这一数据存储结构,作为容器,用以存储、处理大量对象。这些由JDK提供的集合主要围绕着Collection接口和Map接口实现,本节主要介绍由Map接口实现的集合。
在这里插入图片描述

1、Map接口相关继承关系

Map接口下,主要由HashMap类、Hashtable类、TreeMap类等对其进行实现,它们都在java.util包下,它们之间简单的继承关系图可以概括如上图:
说明:
java.util.Map是一个泛型接口,该接口规范了用来存储键值对数据的集合的行为,主要声明了put(K key, V value)、containsKey(Object key)、containsValue(Object value)、get(Object key)、keySet()、entrySet()、remove(Object key)、size()、clear()等方法。实现java.util.Map接口的集合。

java.util.HashMap类、java.util.Hashtable类、java.util.TreeMap类均分别实现了java.util.Map接口。

2、Map接口

实现了java.util.Map接口的集合用于保存具有映射关系的数据,即以键值对(key->value)的方式来存储数据。因此在集合内部有两个集合,一个集合用于保存key(键),一个集合用于保存value(值),实现了java.util.Map接口的集合都具有如下图所示的基本结构:

java.util.Map接口常见的实现类有java.util.HashMap类、java.util.Hashtable类、java.util.TreeMap类等,它们的功能与用法几乎完全相同,只是内部实现不同。

java.util.Map接口中的一些常用API如下:
参考API: JDK 1.8

序号返回值方法方法说明
01voidclear()从这个映射中移除所有的映射(可选操作)。
02default Vcompute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)试图计算出指定键和当前的映射值的映射(或 null如果没有当前映射)。
03default VcomputeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)如果指定的键是不是已经与价值相关的(或映射到 null),尝试使用给定的映射功能,进入到这个Map除非 null计算其价值。
04default VcomputeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)如果指定键的值是存在和非空的,尝试计算一个新的映射,给出了键和它当前的映射值。
05booleancontainsKey(Object key)返回 true如果这Map包含一个指定的键映射。
06booleancontainsValue(Object value)返回 true如果映射到指定的值的一个或多个键。
07Set<Map.Entry<K,V>>entrySet()返回一个 Set视图的映射包含在这个Map
08booleanequals(Object o)将指定的对象与此映射的相等性进行比较。
09default voidforEach(BiConsumer<? super K,? super V> action)在该映射中的每个条目执行给定的操作,直到所有的条目被处理或操作抛出异常。
10Vget(Object key)返回指定的键映射的值,或 null如果这个Map不包含的键映射
12default VgetOrDefault(Object key, V defaultValue)返回指定的键映射的值,或 defaultValue如果这个Map不包含的键映射。
13inthashCode()返回此映射的哈希代码值。
14booleanisEmpty()返回 true如果这个Map不包含键值的映射。
15Set<K>keySet()返回一个 Set的关键视图包含在这个Map。
16default Vmerge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)如果指定的键已与值相关联的值或与空值相关联的,则将其与给定的非空值关联。
17Vput(K key, V value)将指定的值与此映射中的指定键关联(可选操作)。
18voidputAll(Map<? extends K,? extends V> m)从指定的映射到这个Map(可选操作)复制所有的映射
19default VputIfAbsent(K key, V value)如果指定的键是不是已经与价值相关的(或映射到 null)将其与给定的值并返回 null,否则返回当前值
20Vremove(Object key)如果存在(可选操作),则从该Map中移除一个键的映射
21default booleanremove(Object key, Object value)仅当它当前映射到指定的值时,为指定的键移除条目。
22default Vreplace(K key, V value)仅当它当前映射到某一值时,替换指定的键的条目
23default booleanreplace(K key, V oldValue, V newValue)仅当当前映射到指定的值时,替换指定的键的条目
24default voidreplaceAll(BiFunction<? super K,? super V,? extends V> function)将每个条目的值替换为在该项上调用给定函数的结果,直到所有的条目都被处理或函数抛出异常
25intsize()返回这个映射中的键值映射的数目
26Collectionvalues()返回一个 Collection视图的值包含在这个Map。

2.1、HashMap类

java.util.HashMap类借助散列算法实现java.util.Map接口,该类是一个泛型类java.util.HashMap集合在保存键值映射数据时,键(key)无序(这里的无序指元素不具有下标,无法通过下标索引来访问元素)且不可重复,不可重复这一特点由作为键的对象的hashCode()方法和equals(Object obj)方法保证。

下面是一个示例:
Person类的源码:

package com.codeke.java.test;

public class Person {
    private String id;      // 编号
    private String name;    // 名称
    // 构造方法
    public Person(String id, String name) {
        this.id = id;
        this.name = name;
    }
    // 获得编号
    public String getId() {
        return id;
    }
    // 获得名称
    public String getName() {
        return name;
    }
}

测试类Test类的源码:

package com.codeke.java.test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        // 声明Map类型的变量map,并赋值为一个HashMap实例
        // 指定了该集合中key的类型参数为String,value的类型参数为Person
        Map<String, Person> map = new HashMap<String, Person>();
        // 实例化几个Person对象
        Person p1 = new Person("001", "鲁智深");
        Person p2 = new Person("002", "武松");
        Person p3 = new Person("003", "林冲");
        // 向map集合中添加元素
        map.put(p1.getId(), p1);
        map.put(p2.getId(), p2);
        map.put(p3.getId(), p3);
        // 通过key判断集合中是否包含"鲁智深"
        if (map.containsKey(p1.getId())) {
            System.out.println("通过键查找到了鲁智深");
        } else {
            System.out.println("通过键没有查找到了鲁智深");
        }
        // 通过value判断集合中是否包含"史进"
        if (map.containsValue(p1)) {
            System.out.println("通过值查找到了鲁智深");
        } else {
            System.out.println("通过值没有查找到了鲁智深");
        }
        // 从集合map中获取一个元素
        Person person = map.get("001");
        System.out.println("键为001的person,他的姓名是" + person.getName());
        //迭代集合map中所有的对象
        System.out.println("迭代集合中所有的元素");
        // 返回集合map中键(key)所组成的Set集合
        Set<String> set = map.keySet();
        // 获取集合set的迭代器
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            Person p = map.get(key);
            System.out.printf("键:%s 对应的person为: %s\n", key, p.getName());
        }
        // 从集合map中移除p1
        map.remove(p1.getId());
        // 显示移除p1后集合map中元素的个数
        System.out.println("移除p1后集合中还有" + map.size() + "个元素");
    }
}

执行输出结果:

通过键查找到了鲁智深
通过值查找到了鲁智深
键为001的person,他的姓名是鲁智深
迭代集合中所有的元素
键:001 对应的person为: 鲁智深
键:002 对应的person为: 武松
键:003 对应的person为: 林冲
移除p1后集合中还有2个元素

说明:

本例演示了如何实例化java.util.HashMap集合及如何使用Map集合的put(K key, V value)、containsKey(Object key)、get(Object key)、keySet()、remove(Object key)、size()等方法。
注意,Map集合的遍历需要借助Set集合和迭代器java.util.Iterator。
下面是另一个示例:
Person类的源码同上例。
测试类Test类的源码:

package com.codeke.java.test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Test {
    public static void main(String[] args) {
        // 声明Map类型的变量map,并赋值为一个HashMap实例
        // 指定了该集合中key的类型参数为String,value的类型参数为Person
        Map<String, Person> map = new HashMap<String, Person>();
        // 实例化几个Person对象
        Person p1 = new Person("001", "吴用");
        Person p2 = new Person("002", "公孙胜");
        Person p3 = new Person("003", "花荣");
        // 向map集合中添加元素
        map.put("001", p1);
        map.put("002", p2);
        map.put("002", p3);  // 添加key重复的元素
        // 返回集合map中所有键值映射所组成的Set集合
        Set<Map.Entry<String, Person>> entrySet = map.entrySet();
        Iterator<Map.Entry<String, Person>> iterator = entrySet.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Person> entry = iterator.next();
            String key = entry.getKey();
            Person p = entry.getValue();
            System.out.printf("键:%s 对应的person为: %s\n", key, p.getName());
        }
    }
}

执行输出结果:

键:001 对应的person为: 吴用
键:002 对应的person为: 花荣

说明:

实现了java.util.Map接口的集合中键是唯一的,但观察本例中的代码,在将对象p2和p3作为值(value)添加至集合时,所对应的键(key)均为002,这种情况下,后添加入集合的键值映射会覆盖之前存在的键值映射。
本例中还演示了Map集合的entrySet()方法,该方法可以返回集合中所有键值映射所组成的Set集合,该Set集合中的元素即是一对一对的键值映射数据。
java.util.Map接口中有一个内部接口Entry,该接口的实现类可以保存一对键值映射数据,即一个键(key)和对应的一个值(value),该接口中声明的最常用的方法是getKey()方法和getValue()方法,顾名思义,getKey()方法用以获取键(key),getValue()方法用以获取值(value)。

2.2、Hashtable类

java.util.Hashtable类同java.util.HashMap类非常相似,同样借助散列算法实现java.util.Map接口,该类也是一个泛型类;与java.util.HashMap类最核心的不同是,java.util.Hashtable类是线程同步(Thread Synchronized)的,所以它也是线程安全的,而java.util.HashMap类是线程异步(Thread ASynchronized)的,在多线程的场景下不能保证线程安全。

下面是一个示例:
Person类的源码同上例。
测试类Test类的源码:

package com.codeke.java.test;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        // 声明Map类型的变量map,并赋值为一个Hashtable实例
        // 指定了该集合中key的类型参数为String,value的类型参数为Person
        Map<String, Person> map = new Hashtable<String, Person>();
        // 实例化几个Person对象
        Person p1 = new Person("001", "鲁智深");
        Person p2 = new Person("002", "武松");
        Person p3 = new Person("003", "林冲");
        // 向map集合中添加元素
        map.put(p1.getId(), p1);
        map.put(p2.getId(), p2);
        map.put(p3.getId(), p3);
        // 从集合map中获取一个元素
        Person person = map.get("003");
        System.out.println("键为003的person,他的姓名是" + person.getName());
        //迭代集合map中所有的对象
        System.out.println("迭代集合中所有的元素");
        // 返回集合map中所有键值映射所组成的Set集合
        Set<Map.Entry<String, Person>> entrySet = map.entrySet();
        // 用加强型For循环遍历entrySet集合
        for (Map.Entry<String, Person> entry : entrySet) {
            String key = entry.getKey();
            Person p = entry.getValue();
            System.out.printf("键:%s 对应的person为: %s\n", key, p.getName());
        }
        // 从集合map中移除p1
        map.remove(p1.getId());
        // 显示移除p1后集合map中元素的个数
        System.out.println("移除p1后集合中还有" + map.size() + "个元素");
    }
}

执行输出结果:

键为003的person,他的姓名是林冲
迭代集合中所有的元素
键:003 对应的person为: 林冲
键:002 对应的person为: 武松
键:001 对应的person为: 鲁智深
移除p1后集合中还有2个元素

说明:

java.util.Hashtable类的使用与java.util.HashMap类使用方法几乎完全相同,这里不再赘述。

2.3、TreeMap类

java.util.TreeMap类借助二叉树实现java.util.Map接口,该类也是一个泛型类。该类的使用方法与java.util.HashMap类几乎完全相同,不同的是,java.util.TreeMap集合在保存键值映射数据时会对数据按照键(key)进行比较,并按照键的数据类型所实现的比较方式(实现java.lang.Comparable接口)对元素进行排序。

下面是一个示例:
Person类的源码同上例。
测试类Test类的源码:

package com.codeke.java.test;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class Test {

    public static void main(String[] args) {
        // 声明Map类型的变量map,并赋值为一个TreeMap实例
        // 指定了该集合中key的类型参数为String,value的类型参数为Person
        Map<String, Person> map = new TreeMap<String, Person>();
        // 实例化几个Person对象
        Person p1 = new Person("001", "鲁智深");
        Person p2 = new Person("002", "武松");
        Person p3 = new Person("003", "林冲");
        Person p4 = new Person("004", "吴用");
        Person p5 = new Person("005", "公孙胜");
        Person p6 = new Person("006", "史进");
        Person p7 = new Person("007", "花荣");
        Person p8 = new Person("008", "柴进");
        // 向map集合中添加元素
        map.put(p5.getId(), p5);
        map.put(p2.getId(), p2);
        map.put(p1.getId(), p1);
        map.put(p8.getId(), p8);
        map.put(p6.getId(), p6);
        map.put(p3.getId(), p3);
        map.put(p7.getId(), p7);
        map.put(p4.getId(), p4);

        // 返回集合map中所有键值映射所组成的Set集合
        Set<Map.Entry<String, Person>> entrySet = map.entrySet();
        // 用加强型For循环遍历entrySet集合
        for (Map.Entry<String, Person> entry : entrySet) {
            String key = entry.getKey();
            Person p = entry.getValue();
            System.out.printf("键:%s 对应的person为: %s\n", key, p.getName());
        }
    }
}

执行输出结果:

键:001 对应的person为: 鲁智深
键:002 对应的person为: 武松
键:003 对应的person为: 林冲
键:004 对应的person为: 吴用
键:005 对应的person为: 公孙胜
键:006 对应的person为: 史进
键:007 对应的person为: 花荣
键:008 对应的person为: 柴进

说明:

观察本例的代码和执行输出结果,可以看到集合map中的键值映射数据已经按照键(key)进行了排序。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值