Map集合

举报
别团等shy哥发育 发表于 2023/01/08 17:54:39 2023/01/08
【摘要】 @toc 1、Map集合  Map是地图、映射的意思。生活中地图上的某个点可以映射到实际地理环境中的某个位置,这种映射关系可以用(key,value)的键值对来表示。  Map系列的集合就是用来存储键值对的,java.util.Map是Map系列接口的根接口,其中包含一个静态内部接口Entry,它是(key,value)映射关系的根接口,Entry接口中提供了getKey和getValue的...

@toc

1、Map集合

  Map是地图、映射的意思。生活中地图上的某个点可以映射到实际地理环境中的某个位置,这种映射关系可以用(key,value)的键值对来表示。

  Map系列的集合就是用来存储键值对的,java.util.Map是Map系列接口的根接口,其中包含一个静态内部接口Entry,它是(key,value)映射关系的根接口,Entry接口中提供了getKey和getValue的方法,所有实现Map接口的实现类,也都要用内部类实现Entry接口。

  同一个Map中的key是不允许重复的,key和value之间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value,Map中的key和value可以是任何引用类型的数据。一些映射实现可明确保证其顺序,如TreeMap类;另一些映射实现则不保证顺序,如HashMap类。

1.1 Map接口的方法

  既然Map是用来存储Entry类的(key,value)键值对的,那么Map接口中自然也封装了所有键值对的通用操作方法:增、删、改、查、遍历。

  (1)添加操作

  • Object put(Object key,Object value):put一对(key,value)键值对到当前Map集合中,如果这个key在当前map中不存在,则会新添加。
  • void putAll(Map map):将另一个map中的键值对添加到当前Map集合中,如果key相同,则会出现value覆盖的现象。

  (2)删除操作

  • void clear():清空当前map集合。
  • Object remove(Object key):根据指定的key从当前map中删除一对映射关系。

  (3)查询操作

  • Object get(Object key):根据指定的key从当前map中查找其对应的value。
  • boolean containsKey(Object key):判断在当前map中是否存在指定的key.
  • boolean containsValue(Object value):判断在当前map中是否存在指定的value。
  • boolean isEmpty():判断当前map是否为空。

  (4)其他方法

int size():获取当前map中(key,value)的键值对数。

import java.util.HashMap;

public class MapMethodTest {
    public static void main(String[] args) {
        HashMap<Object, Object> map = new HashMap<>();
        map.put("许仙","白娘子");
        map.put("董永","七仙女");
        map.put("牛郎","织女");
        map.put("许仙","玉兔精");

        System.out.println("map:"+map);

        System.out.println("键值对数:"+map.size());
        System.out.println("是否包含key[许仙]:"+map.containsKey("许仙"));
        System.out.println("是否包含value[白娘子]:"+map.containsValue("白娘子"));
        System.out.println("获取[许仙]对应的value:"+map.get("许仙"));

        map.remove("许仙");
        System.out.println("删除[许仙]这对key,value之后的map:"+map);
    }
}

image-20221005134709515

1.2 Map集合的遍历

  Map接口并没有继承Iterator接口,所以并不支持foreach和Iterator遍历。难道之前Collection集合的遍历方式没有可借鉴之处吗?答案当然是否定的。因为Map接口提供三种collection视图,允许以键集、值集和键-值映射关系集的方式查看某个映射的内容。

  (1)分开遍历:又存在两种情况,即单独遍历所有key和单独遍历所有value。

  (2)成对遍历:遍历的是映射关系Map.EntryMap.Entry是Map接口的内部接口。每种Map内部都有自己的Map.Entry的实现类。在Map中存储数据,实际上是将 k e y v a l u e key\to value 的数据存储在Map.Entry接口的实例中,再在Map集合中插入Map.Entry的实例化对象。

  Map接口中有以下三个和遍历相关的方法。

  • Set keySet()
  • Collection values()
  • Set entrySet()

  Map集合遍历的示例代码:

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

public class MapTest {
    public static void main(String[] args) {
        HashMap<Object, Object> map = new HashMap<>();
        map.put("许仙","白娘子");
        map.put("董永","七仙女");
        map.put("牛郎","织女");

        System.out.println("所有的key:");
        Set<Object> keySet = map.keySet();
        for (Object key : keySet) {
            System.out.println("\t"+key);
        }

        System.out.println("所有的value:");
        Collection<Object> values = map.values();
        for (Object value : values) {
            System.out.println("\t"+value);
        }

        System.out.println("所有的映射关系:");
        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        for (Map.Entry<Object, Object> entry : entrySet) {
            System.out.println("\t"+entry);
        }
    }
}

image-20221005135913125

1.3 Map接口的实现类

  Map接口常用的实现类有HashMapTreeMapLinkedHashMapProperties。其中HashMap是Map接口使用频率最高的实现类。接下来介绍下这几个类的主要特点。

1.3.1 HashMap和Hashtable的区别与联系

  HashMap和Hashtable都是哈希表,HashMap和Hashtable的区别如下表所示。

底层结构 线程安全(同步) 版本 效率 key,value是否允许为null
HashMap 哈希表 不安全(不同步) 较新 较高 允许
Hashtable 哈希表 安全(同步) 较老 较低 不允许

  使用HashMap的示例代码(添加员工姓名为key,薪资为value):

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

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Object, Object> map = new HashMap<>();
        map.put("张三",10000);
        map.put("李四",14000);
        map.put(null,null);
        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        for (Map.Entry<Object, Object> object : entrySet) {
            System.out.println(object);
        }
    }
}

image-20221005140531817

1.3.2 LinkedHashMap

  LinkedHashMapHashMap的子类,此实现与HashMap的不同之处在于,LinkedHashMap维护了一个双向链表,此链表定义了迭代顺序,此迭代顺序通常就是将键插入映射中的顺序。

  使用LinkedHashMap的示例代码:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class LinkedHashMapTest {
    public static void main(String[] args) {
        LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
        map.put("张三",10000);
        map.put("李四",14000);

        //遍历发现,可以体现添加顺序,这点和HashMap不同
        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        for (Map.Entry<Object, Object> object : entrySet) {
            System.out.println(object);
        }
    }
}

image-20221005140813044

1.3.3 TreeMap

  TreeMap的集合是基于红黑树(Red-Black tree)的可导航NavigableMap实现的。TreeMap中的映射关系要么根据其key键的自然顺序进行排序,要么根据创建TreeMap对象提供给key键的定制排序Comparator接口实现类进行排序,具体取决于使用的构造方法。

  TreeMap使用key的自然排序的示例代码(其中String类实现了Comparable接口):

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

/**
 * TreeMap使用key的自然排序
 */
public class TreeMapTest1 {
    public static void main(String[] args) {
        TreeMap<Object, Object> map = new TreeMap<>();
        //String实现了Comparable接口,默认按照Unicode编码值排序
         map.put("Jack",11000);
         map.put("Alice",12000);
         map.put("zhangsan",13000);
         map.put("baitao",14000);
         map.put("Lucy",15000);

        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        for (Map.Entry<Object, Object> object : entrySet) {
            System.out.println(object);
        }
    }
}

image-20221005141358502

  TreeMap使用定制排序Comparator的示例代码:

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

/**
 * TreeMap使用定制排序Comparator
 */
public class TreeMapTest2 {
    public static void main(String[] args) {
        //指定定值比较器Comparator,按照Unicode编码值排序,但是忽略大小写
        TreeMap<Object, Object> map = new TreeMap<>(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                String s1 = (String) o1;
                String s2 = (String) o2;
                return s1.compareToIgnoreCase(s2);
            }
        });
        map.put("Jack",11000);
        map.put("Alice",12000);
        map.put("zhangsan",13000);
        map.put("baitao",14000);
        map.put("Lucy",15000);

        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        for (Map.Entry<Object, Object> object : entrySet) {
            System.out.println(object);
        }
    }
}

image-20221005141441491

1.3.4 Properties

  Properties是Hashtable的子类,Properties中存储的数据可保存在流中或从流中加载。Properties的特殊之处在于,它的每个key及其对应的value都是一个字符串。在存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。

  使用Properties的示例代码:

import java.util.Properties;

public class PropertiesTest {
    public static void main(String[] args) {
        Properties properties = System.getProperties();
        String value = properties.getProperty("file.encoding");//当前源文件字符编码
        System.out.println(value);
    }
}

image-20221005141803319

1.4 企业面试题

  案例需求:有一个字符串,它是一句话,包含了空格等标点符号,统计该字符串中出现次数最多的字母和该字母出现的次数,字母不区分大小写形式。请至少使用两种方法来实现。

  方案一:

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

/**
 * 有一个字符串,它是一句话,包含了空格等标点符号,统计该字符串中出现次数最多的字母和该字母出现的次数,
 * 字母不区分大小写形式。
 */
public class MapExer1 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.println("请输入一串字符:");
        String strings = input.nextLine();
        //匹配不在a-z范围内的任意字符,替换为空串
        strings.toLowerCase().replaceAll("[^a-z]","");
        HashMap<Object, Object> map = new HashMap<>();
        char[] arr = strings.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            if(map.containsKey(arr[i])){
                Integer count = (Integer) map.get(arr[i]);
                map.put(arr[i],count+1);
            }else{
                map.put(arr[i],1);
            }
        }
        int maxCount=0;
        Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
        for (Map.Entry<Object, Object> object : entrySet) {
            Map.Entry entry = (Map.Entry)object;
            Character key= (Character) entry.getKey();
            Integer value=(Integer)entry.getValue();
            if(value>maxCount){
                maxCount=value;
            }
        }
        //考虑到最高次数有相同的多个字符
        entrySet= map.entrySet();
        for (Map.Entry<Object, Object> object : entrySet) {
            Map.Entry entry=(Map.Entry) object;
            Character key=(Character)entry.getKey();
            Integer value=(Integer)entry.getValue();
            if(value==maxCount){
                System.out.println("该字符串中出现次数最多的字母是:"+key+",共出现了:"+maxCount);
            }
        }


    }
}

image-20221005142053933

  方案二:

import java.util.Scanner;

public class MapExer2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入一串字符:");
        String strings = input.nextLine();

        strings = strings.toLowerCase().replaceAll("[^a-z]", "");
        char[] letterCounts = new char[26];
        char[] arr = strings.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            letterCounts[arr[i]-97]++;
        }

        int max=0;
        for (int i = 0; i < letterCounts.length; i++) {
            if(max<letterCounts[i]){
                max=letterCounts[i];
            }
        }
        //考虑到最高次数有相同的多个字母
        for(int i=0;i<letterCounts.length;i++){
            if(max==letterCounts[i]){
                System.out.println("该字符串中出现次数最多的字母是:"+(char)(i+97)+",共出现了:"+max);
            }
        }
    }
}

image-20221005142152029

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。