乐趣区

关于java:Java-集合三Map-集合

一、前言

<font face= 黑体 > 汇合依照其存储构造能够分为两大类,别离是单列汇合 java.util.Collection 和双列汇合 java.util.Map,单列汇合咱们曾经讲了,明天咱们来讲双列汇合 Map

二、Map 汇合

2.1、Map 汇合概述

<font face= 黑体 > 现实生活中,咱们常会看到这样的一种汇合:学生与学号,身份证号与集体,这种一一对应的关系,就叫做映射。Java 提供了专门的汇合类用来寄存这种对象关系,即 java.util.Map 接口。咱们来看一下 Map 汇合和 Collection 汇合的区别:

  • <font face= 黑体 >Collection 中的汇合,元素是孤立存在的,向汇合中存储元素采纳一个个元素的形式存储。
  • <font face= 黑体 >Map 中的汇合,元素是成对存在的。每个元素由键与值两局部组成,通过键能够找到对应的值。
  • <font face= 黑体 >Collection 中的汇合称为单列汇合,Map 中的汇合称为双列汇合。
  • <font face= 黑体 > 须要留神的是,Map 中的汇合不能蕴含反复的键,值能够反复,每个键只能对应一个值。

<font face= 黑体 >Map 接口中的汇合都有两个泛型变量 <K,V>,在应用时,要为两个泛型变量赋予数据类型。两个泛型变量 <K,V> 的数据类型能够雷同,也能够不同。

2.2、Map 接口罕用实现类

<font face= 黑体 >Map 有多个子类,这里咱们次要解说罕用的 HashMap 汇合和 LinkedHashMap 汇合。

  • <font face= 黑体 >HashMap<K,V>:存储数据采纳的是哈希表构造,元素的存取程序有可能不统一(无序)。因为要保障键的惟一、不反复,须要重写键的hashCode() 办法和 equals() 办法。
  • <font face= 黑体 >LinkedHashMap<K,V>HashMap下有个子类 LinkedHashMap,存储数据采纳的是哈希表构造 + 链表构造。通过链表构造能够保障元素的存取程序统一,通过哈希表构造能够保障键的惟一、不反复,须要重写键的hashCode() 办法和 equals() 办法。

<font face= 黑体 > 能够类比 HashSetLinkedHashSet

2.3、Map 接口中的罕用办法

<font face= 黑体 >Map 接口中定义了很多办法,罕用的如下:

  • <font face= 黑体 >public V put(K key, V value): 把指定的键与指定的值增加到 Map 汇合中,存储键值对的时候如果 key 不反复,返回值 v null,如果 key 反复,返回值 v 是 被替换的 value 值。

    private static void show01() {
        // 创立 Map 汇合
        Map<String, String> map = new HashMap<>();
        String v1 = map.put("至尊宝", "晶晶");
        System.out.println(v1); // 返回 null
        // 这时候 晶晶 会被 紫霞仙子 替换,返回被替换的 value 值 晶晶
        String v2 = map.put("至尊宝", "紫霞仙子");
        System.out.println(v2); // 返回 晶晶
        System.out.println(map); // 返回 {至尊宝 = 紫霞仙子}
        
        // key 不容许反复,value 能够反复
        map.put("孙悟空", "紫霞仙子");
        System.out.println(map); // 返回 {至尊宝 = 紫霞仙子, 孙悟空 = 紫霞仙子}
    }
  • <font face= 黑体 >public V remove(Object key): 将指定的键所对应的元素在 Map 汇合中删除,返回被删除元素的值。

    private static void show02() {Map<String, Integer> map = new HashMap<>();
        map.put("王祖贤", 175);
        map.put("林青霞", 168);
        map.put("李嘉欣", 172);
        System.out.println(map); // 返回 {林青霞 =168, 李嘉欣 =172, 王祖贤 =175}
    
        Integer v1 = map.remove("李嘉欣");
        System.out.println(v1); // 返回 172
        System.out.println(map); // 返回 {林青霞 =168, 王祖贤 =175}
    
        Integer v2 = map.remove("李嘉诚");
        System.out.println(v2); // 返回 null
        System.out.println(map); // 返回 {林青霞 =168, 王祖贤 =175}
    }
  • <font face= 黑体 >public V get(Object key) 依据指定的键,在 Map 汇合中获取对应的值。

    private static void show03() {Map<String, String> map = new HashMap<>();
        map.put("邓超", "孙俪");
        map.put("吴奇隆", "刘诗诗");
        map.put("黄晓明", "杨颖");
    
        String v1 = map.get("吴奇隆"); // 返回 刘诗诗
        System.out.println(v1);
    
        String v2 = map.get("胡歌"); // 返回 null
        System.out.println(v2);
    }
  • <font face= 黑体 >boolean containsKey(Object key) 判断汇合中是否蕴含指定的键。

    private static void show04() {Map<String, String> map = new HashMap<>();
        map.put("邓超", "孙俪");
        map.put("吴奇隆", "刘诗诗");
        map.put("黄晓明", "杨颖");
    
        System.out.println(map.containsKey("邓超")); // 返回 true
        System.out.println(map.containsKey("胡歌")); // 返回 false
    }
  • <font face= 黑体 >public Set<K> keySet(): 获取 Map 汇合中所有的键,存储到 Set 汇合中。(遍历汇合时具体解说)
  • <font face= 黑体 >public Set<Map.Entry<K,V>> entrySet(): 获取到 Map 汇合中所有的键值对对象并存储到 Set 汇合中。(遍历汇合时具体解说)

2.4、Map 汇合的遍历

2.4.1、通过 keySet() 办法遍历 Map 汇合

<font face= 黑体 > 通过 keySet() 办法遍历 Map 汇合也称键找值形式:即通过元素中的键,获取键所对应的值。

<font face= 黑体 > 具体步骤如下:

  1. <font face= 黑体 > 通过 keyset() 办法获取 Map 中所有的键,并存储到一个 Set 汇合中;
  2. <font face= 黑体 > 遍历 Set 汇合,失去每一个键;
  3. <font face= 黑体 > 通过 get(K key) 办法,获取键所对应的值。

<font face= 黑体 > 图示如下:

<font face= 黑体 > 通过 keySet() 办法遍历 Map 汇合代码演示如下所示:

public class MapDemo02 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();
        map.put("邓超", "孙俪");
        map.put("吴奇隆", "刘诗诗");
        map.put("黄晓明", "杨颖");

        // 1、通过 keyset() 办法获取 Map 中所有的键,并存储到一个 Set 汇合中;Set<String> set = map.keySet();
        // 2、遍历 Set 汇合,失去每一个键;Iterator<String> it = set.iterator();
        while (it.hasNext()) {String key = it.next();
            // 3、通过 get(K key) 办法,获取键所对应的值。String value = map.get(key);
            System.out.println(key + "=" + value);
        }

        System.out.println();
        System.out.println("--------------------- 分割线 -----------------------");
        System.out.println();

        // 应用加强 for
        for (String key : set) {String value = map.get(key);
            System.out.println(key + "=" + value);
        }
    }
}

<font face= 黑体 > 应用加强 for 循环简化上述遍历代码:

public class MapDemo02 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();
        map.put("邓超", "孙俪");
        map.put("吴奇隆", "刘诗诗");
        map.put("黄晓明", "杨颖");
        
        for (String key : map.keySet()) {String value = map.get(key);
            System.out.println(key + "=" + value);
        }
    }
}

2.4.2、Entry 键值对对象

<font face= 黑体 >EntryMap 接口中的外部接口, 咱们曾经晓得,Map 中寄存的是两种对象,一种称为 key(键),一种称为 value(值),它们在Map 中是一一对应关系,这一对象又称做 Map 中的一个 Entry(项)Entry 将键值对的对应关系封装成了对象。即键值对对象,这样咱们在遍历 Map 汇合时,就能够从每一个键值对(Entry)对象中获取对应的键与对应的值。

<font face= 黑体 >Entry 示意一对键和值,提供了获取对应键和对应值的办法:

  • <font face= 黑体 >public K getKey():获取 Entry 对象中的键。
  • <font face= 黑体 >public V getValue():获取 Entry 对象中的值。

2.4.3、通过 entrySet() 办法遍历 Map 汇合

<font face= 黑体 > 在 Map 汇合中提供了获取所有 Entry 对象的办法:

  • <font face= 黑体 >public Set<Map.Entry<K,V>> entrySet(): 获取 Map 汇合中所有的键值对对象并存储到 Set 汇合中。

<font face= 黑体 > 通过 entrySet() 办法遍历 Map 汇合也称 键值对形式:即通过汇合中每个键值对 (Entry) 对象,获取键值对对象中的键与值。

<font face= 黑体 > 具体步骤如下:

  1. <font face= 黑体 > 应用 Map 汇合中的 entrySet() 办法,把 Map 汇合中的所有 Entry 对象取出来,存储到一个 Set 汇合中。
  2. <font face= 黑体 > 遍历蕴含键值对对象的 Set 汇合,获取每一个键值对对象。
  3. <font face= 黑体 > 通过键值对对象的 getKey() 办法和 getValue() 办法获取键与值。

<font face= 黑体 > 通过 entrySet() 办法遍历 Map 汇合代码演示如下所示:

public class MapDemo03 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();
        map.put("邓超", "孙俪");
        map.put("吴奇隆", "刘诗诗");
        map.put("黄晓明", "杨颖");

        // 1、应用 Map 汇合中的 entrySet() 办法,把 Map 汇合中的所有 Entry 对象取出来,存储到一个 Set 汇合中
        Set<Map.Entry<String, String>> set = map.entrySet();
        // 2、遍历蕴含键值对对象的 Set 汇合,获取每一个键值对对象
        Iterator<Map.Entry<String, String>> it = set.iterator();
        while (it.hasNext()) {Map.Entry<String, String> entry = it.next();
            // 3、通过键值对对象的 `getKey()` 办法和 `getValue()` 办法获取键与值。String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
    }
}

<font face= 黑体 > 应用加强 for 循环简化上述遍历代码:

public class MapDemo03 {public static void main(String[] args) {Map<String, String> map = new HashMap<>();
        map.put("邓超", "孙俪");
        map.put("吴奇隆", "刘诗诗");
        map.put("黄晓明", "杨颖");

        for (Map.Entry<String, String> entry : map.entrySet()) {System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }
}

2.5、HashMap 存储自定义类型的键值

<font face= 黑体 >Map 汇合要保障 key 是惟一的,即作为 key 的元素必须得重写 hashCode() 办法和 equals() 办法。

<font face= 黑体 >HashMap 存储自定义类型代码演示如下所示:

public class Student {

    private String name;
    private int age;

    public Student() {}

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {return name;}

    public void setName(String name) {this.name = name;}

    public int getAge() {return age;}

    public void setAge(int age) {this.age = age;}

    @Override
    public int hashCode() {return Objects.hash(name, age);
    }

    @Override
    public boolean equals(Object o) {if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public static void main(String[] args) {//show01();
        show02();}

    /**
     * HashMap 存储自定义类型的键值
     * key:String 曾经重写了 hashCode() 和 equals()
     * value: 应用 Student value 能够反复(同名同年龄的人就视为反复)*/
    private static void show01() {
        // 创立 hashMap 汇合
        HashMap<String, Student> map = new HashMap<String, Student>();
        map.put("北京", new Student("张三", 18));
        map.put("上海", new Student("李四", 19));
        map.put("广州", new Student("王五", 20));
        map.put("北京", new Student("赵六", 18));
        // 应用 keySet() 遍历汇合
        for (String key : map.keySet()) {System.out.println(key + "-->" + map.get(key));
        }
    }

    /**
     * HashMap 存储自定义类型的键值
     * key: 应用 Student Student 必须重写 hashCode 和 equals 办法保障 key 惟一
     * value: 应用 String
     */
    private static void show02() {
        // 创立 hashMap 汇合
        HashMap<Student, String> map = new HashMap<Student, String>();
        map.put(new Student("张三", 18), "北京");
        map.put(new Student("李四", 19), "上海");
        map.put(new Student("王五", 20), "广州");
        map.put(new Student("张三", 18), "深圳");
         // 应用 entrySet() 遍历汇合
        for (Map.Entry<Student, String> entry : map.entrySet()) {System.out.println(entry.getKey() + "-->" + entry.getValue());
        }
    }
}

<font face= 黑体 > 打印后果如下所示,因为 String 类和 Student 类都重写了 hashCode() 办法和 equals() 办法,所以存储雷同的 key 的时候,前面的 value 就会替换后面的 value,即 “ 赵六 ” 会替换 “ 张三 ”,” 深圳 ” 会替换 “ 北京 ”。

2.5、LinkedHashMap 汇合

<font face= 黑体 > 在 HashMap 上面有一个子类 LinkedHashMap,它是链表和哈希表组合的一个数据存储构造,它是有序的。

<font face= 黑体 >LinkedHashMap 汇合代码演示如下所示:

public class LinkedHashMapDemo01 {public static void main(String[] args) {HashMap<String, String> map = new HashMap<>();
        map.put("a", "a");
        map.put("c", "c");
        map.put("b", "b");
        map.put("d", "d");
        System.out.println(map); // 返回 {a=a, b=b, c=c, d=d}

        LinkedHashMap<String, String> map1 = new LinkedHashMap<>();
        map1.put("a", "a");
        map1.put("c", "c");
        map1.put("b", "b");
        map1.put("d", "d");
        System.out.println(map1); // 返回 {a=a, c=c, b=b, d=d}
    }
}

2.6、HashTable 汇合

<font face= 黑体 >HashTable 也是继承自 Map 接口的,底层也是一个哈希表,跟 HashMap 的区别如下:

  1. <font face= 黑体 > 键和值都不容许存储 null
  2. <font face= 黑体 > 线程平安,速度慢。

<font face= 黑体 >HashTable 汇合 和 Vector 汇合一样,曾经被更先进的汇合(HashMapArrayList)所取代。

<font face= 黑体 >HashTable 汇合代码演示如下所示:

public class HashTableDemo01 {public static void main(String[] args) {HashMap<String, String> map = new HashMap<String, String>();
        map.put(null, "a");
        map.put("b", null);
        map.put(null, null);
        System.out.println(map); // 返回 {null=null, b=null}

        Hashtable<String, String> map2 = new Hashtable<String, String>();
        map2.put(null, "a"); // 报错 NullPointerException
        map2.put("b", null); // 报错 NullPointerException
        map2.put(null, null); // 报错 NullPointerException
    }
}

三、Map 汇合练习

<font face= 黑体 > 需要:

<font face= 黑体 > 计算一个字符串中每个字符呈现的次数。

<font face= 黑体 > 实现步骤:

  1. <font face= 黑体 > 获取一个字符串对象;
  2. <font face= 黑体 > 创立一个 Map 汇合,键代表字符,值代表次数;
  3. <font face= 黑体 > 遍历字符串失去每个字符;
  4. <font face= 黑体 > 判断 Map 中是否有该键;
  5. <font face= 黑体 > 如果没有,第一次呈现,存储次数为 1;如果有,则阐明曾经呈现过,获取到对应的值进行 ++,再次存储;
  6. <font face= 黑体 > 打印最终后果。

    <font face= 黑体 > 代码实现:

public class ExampleDemo01 {public static void main(String[] args) {
        // 1、应用 Scanner 获取一个字符串对象;Scanner sc = new Scanner(System.in);
        System.out.println("请输出一个字符串:");
        String str = sc.next();

        // 2、创立一个 Map 汇合,键代表字符,值代表次数;HashMap<Character, Integer> map = new HashMap();

        // 3、遍历字符串失去每个字符;for (char c : str.toCharArray()) {
            // 4、判断 Map 中是否有该键;if (map.containsKey(c)) {Integer value = map.get(c);
                value++;
                map.put(c, value);
            } else {map.put(c, 1);
            }
        }

        // 5、打印最终后果。for (Character key : map.keySet()) {System.out.println(key + "-->" + map.get(key));
        }
    }
}

四、源码

<font face= 黑体 > 文章中用到的所有源码已上传至 github,有须要的能够去下载。

退出移动版