• Java集合框架——Map接口


    第三阶段 JAVA常见对象的学习

    集合框架——Map集合

    在实际需求中,我们常常会遇到这样的问题,在诸多的数据中,通过其编号来寻找某一些信息,从而进行查看或者修改,例如通过学号查询学生信息。今天我们所介绍的Map集合就可以很好的帮助我们实现这种需求

    (一) 概述及功能

    (1) 概述

    Map是一种存储元素对的集合(元素对分别称作 键 和 值 也称键值对)它将键映射到值的对象。一个映射不能包含重复的键,并且每个键最 多只能映射到一个值。

    怎么理解呢?

    键 (key):就是你存的值的编号 值 (value):就是你要存放的数据

    你可以近似的将键理解为下标,值依据键而存储,每个键都有其对应值。这两者是1、1对应的

    但在之前下标是整数,但是Map中键可以使任意类型的对象。

    Map集合和Collection集合的区别?

    • Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的
    • Collection集合存储元素是单独出现的,Collection的子类Set是唯一的,List是可重复的。
    • Map集合的数据结构值针对键有效,跟值无关,Collection集合的数据结构是针对元素有效

    (2) 功能

    A:添加功能

    //添加元素
    V put(K key,V value)   
        
    //如果键是第一次存储,就直接存储元素,返回null
    //如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值 
    

    B:删除功能

    //移除所有的键值对元素
    void clear()
    
    //根据键删除键值对元素,并把值返回
    V remove(Object key)
    

    C:判断功能

    //判断集合是否包含指定的键
    boolean containsKey(Object key)
    
    //判断集合是否包含指定的值
    boolean containsValue(Object value)
    
    //判断集合是否为空
    boolean isEmpty()
    

    D:获取功能

    //将map集合中的键和值映射关系打包为一个对象
    Set<Map.Entry<K,V>> entrySet()
    
    //根据键获取值
    V get(Object key)
    
    //获取集合中所有键的集合
    Set<K> keySet()
    
    //获取集合中所有值的集合
    Collection<V> values()
    

    E:长度功能

    //返回集合中的键值对的对数
    int size()
    

    (二) Map集合的遍历

    package cn.bwh_01_iterator;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    public class MapDemo {
        public static void main(String[] args) {
            Map<String, String> hm = new HashMap<String, String>();
            hm.put("bwh002", "i");
            hm.put("bwh001", "love");
            hm.put("bwh003", "you");
    
            //方式一 键找值
            Set<String> set = hm.keySet();
    
            //迭代器遍历
            Iterator<String> it = set.iterator();
            while (it.hasNext()) {
                String key = it.next();
                String value = hm.get(key);
                System.out.println(key + "---" + value);
            }
    
            //增强for遍历
            for (String key : set) {
                String value = hm.get(key);
                System.out.println(key + "---" + value);
            }
    
            //方式二 键值对对象找键和值(推荐)
            Set<Map.Entry<String, String>> set2 = hm.entrySet();
    
            //迭代器遍历
            Iterator<Map.Entry<String, String>> it2 = set2.iterator();
            while (it2.hasNext()) {
                //返回的是封装了key和value对象的Map.Entry对象
                Map.Entry<String, String> entry = it2.next();
                String key = entry.getKey();
                String value = entry.getValue();
                System.out.println(key + "---" + value);
    
            }
    
            //增强for遍历
            for (Map.Entry<String, String> me : set2) {
                String key = me.getKey();
                String value = me.getValue();
                System.out.println(key + "---" + value);
            }
        }
    }
    

    (三) Map及子类总结

    Map(双列集合)

    • Map集合的数据结构仅仅针对键有效,与值无关。

    • 存储的是键值对形式的元素,键唯一,值可重复

    HashMap

    • 底层数据结构是哈希表,线程不安全,效率高

    • 哈希表依赖两个方法:hashCod()和equals()

    • 执行顺序:

      • 首先判断hashCode()值是否相同
        • 是:继续执行equals(),看其返回值
          • 是true:说明元素重复,不添加
          • 是false:就直接添加到集合
        • 否:就直接添加到集合
    • 最终:

    • 自动生成hashCode()和equals()即可

    LinkeHashMap

    • 底层数据结构是由链表和哈希表组成

    • 由链表保证元素有序

    • 由哈希表保证元素唯一

    Hashtable

    • 底层数据结构是哈希表
    • 哈希表依赖两个......自动生成hashCode()和equals()即可

    TreeMap

    • 底层数据结构是红黑树(是一种自平衡的二叉树)

    如何保证元素唯一性呢?

    • 根据比较的返回值是否是0来决定

    如何保证两种元素的排序呢?

    • 自然排序(元素具备比较性)
      • 让元素所属的类实现comparable接口
    • 比较器排序(集合具备比较性)
      • 让集合接收一个comparator的实现类对象

    可以多层嵌套

    HashMap集合嵌套HashMap

    HashMap集合嵌套ArrayList

    ArrayList集合嵌套HashMap

    HashMap<String, ArrayList> hm = new HashMap<String, ArrayList>

    1:Hashtable和HashMap的区别?

    **Hashtable**:线程安全,效率低。不允许null键和null值
    
    **HashMap**:线程不安全,效率高。允许null键和null值
    

    (其实HashMap就是用来替代Hashtable的,就像ArrayList替代vector一样)

    2:List,Set,Map等接口是否都继承子Map接口?

    List,Set不是继承自Map接口,它们继承自Collection接口

    Map接口本身就是一个顶层接口

    需要排序:TreeMap

    不需要排序:HashMap

    不知道具体需求:HashMap

    (四) 经典案例

    (1) 统计字符串中字符出现的次数

    import java.util.Map;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.TreeMap;
    
    /*
     * 案例(统计字符串中字符出现的次数)
     * 需求:
     *      获取一个字符串出现的次数
     * 分析:
     *      A:定义一个字符串(或者键盘录入)
     *      B: 定义一个TreeMap集合
     *              键:Character
     *              值:Integer
     *      C:把字符串转换为字符数组
     *      D: 遍历字符数组,得到每一个字符
     *      E: 拿刚才得到的字符作为键去集合中找,看返回值
     *              是 null:说明该键不存在,就把该字符串作为键,1作为值去存储
     *              不是 null:说明该键存在,就把值加 1 然后重写存储该键和值
     *      F: 定义字符串缓冲区变量
     *      G:遍历集合,得到该建和值,按照要求拼接
     *      H:最后把字符串缓冲区转换为字符串输出
     */
     
    public class CountDemo {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入需要统计的数据");
            String line = sc.nextLine();
    
            Map<Character, Integer> tm = new TreeMap<Character, Integer>();
            char[] chs = line.toCharArray();
            for (char ch : chs) {
                Integer i = tm.get(ch);
                if (i == null) {
                    tm.put(ch, 1);
                } else {
                    i++;
                    tm.put(ch, i);
                }
            }
    
            StringBuilder s = new StringBuilder();
            Set<Character> set = tm.keySet();
            for (Character key : set) {
                Integer value = tm.get(key);
                s.append(key).append("(").append(value).append(")" + " ");
            }
            String result = s.toString();
            System.out.println("result: " + result);
        }
    }
    
    //运行结果
    请输入需要统计的数据
    HelloWorld
    result: H(1) W(1) d(1) e(1) l(3) o(2) r(1) 
    

    (2) 模拟斗地主案例

    在讲解这个案例之前,我们先来了解一个我们下面案例中所需要知道的知识点

    Collections 工具类

    Collections:是针对集合进行操作的工具类,都是静态方法。

    面试题:

    Collection和Collections的区别?

    Collection:是单列集合的顶层接口,有子接口List和Set。(Map是双列的)

    Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法

    Collections的静态方法

    //排序 默认情况下是自然顺序。
    public static <T> void sort(List<T> list)
    
    //二分查找
    public static <T> int binarySearch(List<?> list,T key)
    
    //最大值
    public static <T> T max(Collection<?> coll)
    
    //反转(逆序排序)
    public static void reverse(List<?> list)
    
    //随机置换(犹如洗牌,每次运行结果不一样)
    public static void shuffle(List<?> list)
    
    如果同时有自然排序和比较器排序,以比较器排序为主(也就是说,当同时实现了Student类的自然排序(implements Comparable<Student>)以及比较器排序的话(new Comparator<Student>()),比较器排序会覆盖自然排序)
    
    //斗地主案例代码
    package cn.bwh_03_PokerGame;
    
    import java.util.*;
    
    public class PokerGame {
        public static void main(String[] args) {
            HashMap<Integer, String> hm = new HashMap<Integer, String>();
            ArrayList<Integer> array = new ArrayList<Integer>();
    
            String[] colors = {"♥", "♠", "♣", "♦"};
            String[] numbers = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
    
            int index = 0;
            for (String number : numbers) {
                for (String color : colors) {
                    String poker = color.concat(number);
                    hm.put(index, poker);
                    array.add(index);
                    index++;
                }
            }
    
            hm.put(index, "小王");
            array.add(index);
            index++;
            hm.put(index, "大王");
            array.add(index);
            index++;
    
            //洗牌
            Collections.shuffle(array);
    
            //发牌(发的是编号,为了保证编号是排序的,使用TreeSet接收)
            TreeSet<Integer> player1 = new TreeSet<Integer>();
            TreeSet<Integer> player2 = new TreeSet<Integer>();
            TreeSet<Integer> player3 = new TreeSet<Integer>();
            TreeSet<Integer> handcards = new TreeSet<Integer>();
    
            for (int x = 0; x < array.size(); x++) {
                if (x >= array.size() - 3) {
                    handcards.add(array.get(x));
                } else if (x % 3 == 0) {
                    player1.add(array.get(x));
                } else if (x % 3 == 1) {
                    player2.add(array.get(x));
                } else if (x % 3 == 2) {
                    player3.add(array.get(x));
                }
            }
    
            System.out.println("---------------------欢乐斗地主----------------------");
            //看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
            lookpocker("player1", player1, hm);
            lookpocker("player2", player2, hm);
            lookpocker("player3", player3, hm);
            lookpocker("预留", handcards, hm);
        }
    
        //看牌功能实现
        public static void lookpocker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) {
            System.out.println(name + "的牌是:");
            for (Integer key : ts) {
                String value = hm.get(key);
                System.out.print(value + " ");
            }
            System.out.println();
        }
    }
    

    结尾:

    如果内容中有什么不足,或者错误的地方,欢迎大家给我留言提出意见, 蟹蟹大家 !_

    如果能帮到你的话,那就来关注我吧!(系列文章均会在公众号第一时间更新)

    在这里的我们素不相识,却都在为了自己的梦而努力 ❤

    一个坚持推送原创Java技术的公众号:理想二旬不止

  • 相关阅读:
    Go中的interface学习
    Go中的命名规范
    Go中的结构体
    Go中的文件读写
    Go包管理工具dep
    SpringBoot中读取配置文件的几种方式
    Go标准库--net/http学习
    centos7通过yum安装docker
    scala之构造器详解
    解决!!-- krb5-libs.x86_64被卸载,yum不能使用,ssh不能连接
  • 原文地址:https://www.cnblogs.com/ideal-20/p/11161598.html
Copyright © 2020-2023  润新知