Map集合

简介: 同一个Map中的key是不允许重复的,key和value之间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value,Map中的key和value可以是任何引用类型的数据。是Map系列接口的根接口,其中包含一个静态内部接口Entry,它是(key,value)映射关系的根接口,Entry接口中提供了getKey和getValue的方法,所有实现Map接口的实现类,也都要用内部类实现Entry接口。:将另一个map中的键值对添加到当前Map集合中,如果key相同,则会出现value覆盖的现象。

@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中存储数据,实际上是将$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

目录
相关文章
|
2月前
Map集合的简述
Map集合的简述
|
7天前
|
Dart
Dart之集合详解(List、Set、Map)
Dart之集合详解(List、Set、Map)
13 1
|
13天前
|
存储 JavaScript 前端开发
JavaScript进阶-Map与Set集合
【6月更文挑战第20天】JavaScript的ES6引入了`Map`和`Set`,它们是高效处理集合数据的工具。`Map`允许任何类型的键,提供唯一键值对;`Set`存储唯一值。使用`Map`时,注意键可以非字符串,用`has`检查键存在。`Set`常用于数组去重,如`[...new Set(array)]`。了解它们的高级应用,如结构转换和高效查询,能提升代码质量。别忘了`WeakMap`用于弱引用键,防止内存泄漏。实践使用以加深理解。
|
7天前
|
存储 消息中间件 算法
Java中的集合框架详解:List、Set、Map的使用场景
Java中的集合框架详解:List、Set、Map的使用场景
|
8天前
|
缓存 Java 测试技术
探讨Java中遍历Map集合的最快方式
探讨Java中遍历Map集合的最快方式
10 1
|
22天前
|
存储 缓存 Java
Java遍历Map集合的方法
在Java中,遍历Map集合主要有四种方式:1) 使用`keySet()`遍历keys并用`get()`获取values;2) 使用`entrySet()`直接遍历键值对,效率较高;3) 通过`Iterator`遍历,适合在遍历中删除元素;4) Java 8及以上版本可用`forEach`和Lambda表达式,简洁易读。`entrySet()`通常性能最佳,而遍历方式的选择应考虑代码可读性和数据量。
29 0
|
21天前
|
存储 安全 Java
Java集合详解:Set, Map, Vector, List的对比与联系
Java集合框架核心包括List、Set、Map和Vector。List允许重复元素,如ArrayList(适合读取)和LinkedList(适合插入删除)。Set不允许重复,有HashSet(无序)和TreeSet(排序)。Map存储键值对,HashMap(无序)和TreeMap(排序)。Vector是线程安全的ArrayList替代品,但在多线程环境下使用。选择集合类型应根据应用场景,如有序、无序、键值对需求及线程安全考虑。
|
24天前
|
存储 安全 Java
Java 集合(List、Set、Map 等)相关问答归纳再整理
HashMap 中使用键对象来计算 hashcode 值 HashSet 使用成员对象来计算 hashcode 值,对于两个对象来说hashcode 可能相同,所以 equals() 方法用来判断对象的相等性,如果两个对象不同的话,那么返回 false。 HashMap 比较快,因为是使用唯一的键来获取对象,HashSet 较 HashMap 来说比较慢。 4.1.3 HashMap 与 TreeMap
13 2
|
25天前
|
存储 Java 索引
JavaSE——集合框架二(3/6)-Map系列集合:概述、常用方法(认识Map集合,在什么情形下使用,Map集合体系,Map集合体系的特点)
JavaSE——集合框架二(3/6)-Map系列集合:概述、常用方法(认识Map集合,在什么情形下使用,Map集合体系,Map集合体系的特点)
36 1
|
5天前
|
前端开发
Request获取Map集合,提取username后面的值方法,post和get提取集合的方法
Request获取Map集合,提取username后面的值方法,post和get提取集合的方法