Bootstrap

JAVA基础-Map集合

双列集合

  1. 双列集合一次需要存一对数据,分别为键和值
  2. 键不能重复,值可以重复
  3. 键和值是一一对应的,每一个键只能找到自己对应的值
  4. 键+值这个整体 我们称之为“键值对”或者“键值对对象”,在]ava中叫做"Entry对象"

在这里插入图片描述

1. Map集合

1.1 概述

  • Map集合概述

    interface Map<K,V>  K:键的类型;V:值的类型
    

    Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的

1.2 Map集合的常见API

  • 方法介绍

    方法名说明
    V put(K key,V value)添加元素
    V remove(Object key)根据键删除键值对元素
    void clear()移除所有的键值对元素
    boolean containsKey(Object key)判断集合是否包含指定的键
    boolean containsValue(Object value)判断集合是否包含指定的值
    boolean isEmpty()判断集合是否为空
    int size()集合的长度,也就是集合中键值对的个数
  • 示例代码

    添加元素put(K key,V value):

    在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
    在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。

  //创建集合对象
  Map<String,String> map = new HashMap<String,String>();
   //V put(K key,V value):添加元素
  map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
  map.put("杨过","小龙女");
  

删除元素:返回已经被删除的元素

   String result = m.remove("郭靖");
   System.out.println(result);//黄蓉

判断是否包含

  //判断是否包含
  boolean keyResult = m.containsKey("郭靖");
System.out.println(keyResult);//true存在这个键
  boolean valueResult = m.containsValue("小龙女2");
  System.out.println(valueResult);//false不存在这个值

1.3 Map集合的获取功能

  • 方法介绍

    方法名说明
    V get(Object key)根据键获取值
    Set keySet()获取所有键的集合
    Collection values()获取所有值的集合
    Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合
1.3.1 Map集合的遍历(方式1)
  • 步骤分析

    • 获取所有键的集合。用keySet()方法实现
    • 遍历键的集合,获取到每一个键。用增强for实现
    • 根据键去找值。用get(Object key)方法实现
  • 代码实现

    //1.创建Map集合的对象
    Map<String,String> map=new HashMap<>();
    //2.添加元素
    map.put("尹志平","小龙女");
    map.put("郭靖","穆念慈");
    map.put("欧阳克","黄蓉");
    //3.通过键找值
    //3.1获取所有的键,把这些键放到一个单列集合当中
    Set<String> keys = map.keySet();
    //3.2遍历单列集合,得到每一个键
    for (String key : keys) {
        //System.out.println(key);
        //3.3 利用map集合中的键获取对应的值  get
        String value = map.get(key);
        System.out.println(key + " = " + value);
    }
    //装着键的单列集合使用迭代器的形式进行遍历
    Iterator<String> it=keys.iterator();
    while (it.hasNext()){
        String key=it.next();
        String value=map.get(key);
        System.out.println(key+"="+value);
    }
    //装着键的单列集合使用lambda表达式的形式进行遍历
    keys.forEach(key ->  {
                         String value=map.get(key);
                         System.out.println(key + " = " + value);}
    );
    
1.3.2 Map集合的遍历(方式2)
  • 步骤分析

    • 获取所有键值对对象的集合
      • Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
    • 遍历键值对对象的集合,得到每一个键值对对象
      • 用增强for实现,得到每一个Map.Entry
    • 根据键值对对象获取键和值
      • 用getKey()得到键
      • 用getValue()得到值
  • 代码实现

       //1.创建Map集合的对象
       Map<String, String> map = new HashMap<>();
       //2.添加元素
       map.put("标枪选手", "马超");
     map.put("人物挂件", "明世隐");
       map.put("御龙骑士", "尹志平");
       //3.Map集合的第二种遍历方式
       //通过键值对对象进行遍历
       //3.1 通过一个方法获取所有的键值对对象,返回一个Set集合
     Set<Map.Entry<String, String>> entries = map.entrySet();
       //3.2 遍历entries这个集合,去得到里面的每一个键值对对象
       for (Map.Entry<String, String> entry : entries) {//entry  --->  "御龙骑士","尹志平"
           //3.3 利用entry调用get方法获取键和值
           String key = entry.getKey();
           String value = entry.getValue();
           System.out.println(key + "=" + value);
       }
       //装着键值对对象的单列集合使用迭代器的形式进行遍历
       Iterator<Map.Entry<String,String>> it=entries.iterator();
       while (it.hasNext()){
           Map.Entry<String ,String> entry=it.next();
           String key=entry.getKey();
           String value=entry.getValue();
           System.out.println(key + "=" + value);
       }
       //装着键值对对象的单列集合使用lambda的形式进行遍历
       entries.forEach(entry->{
           String key=entry.getKey();
           String value=entry.getValue();
           System.out.println(key + "=" + value);
               }
       );
    
1.3.3 Map集合的遍历(方式3)

用内部的lamda表达式来遍历

  //Map集合的第三种遍历方式
  //1.创建Map集合的对象
  Map<String,String> map = new HashMap<>();
  //2.添加元素
  //键:人物的名字
  //值:名人名言
  map.put("鲁迅","这句话是我说的");
  map.put("曹操","不可能绝对不可能");
  map.put("刘备","接着奏乐接着舞");
  map.put("柯镇恶","看我眼色行事");
  //3.利用lambda表达式进行遍历
  //底层:
  //forEach其实就是利用第二种方式进行遍历,依次得到每一个键和值
  //再调用accept方法
  map.forEach(new BiConsumer<String, String>() {
      @Override
      public void accept(String key, String value) {
          System.out.println(key + "=" + value);
      }
  });
  System.out.println("-----------------------------------");
//简化1
  map.forEach((String key, String value)->{
          System.out.println(key + "=" + value);
      }
  );
  System.out.println("-----------------------------------");
//简化2
  map.forEach((key, value)-> System.out.println(key + "=" + value));

2.HashMap集合

2.1 概述

  • HashMap是Map里面的一个实现类
  • 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
  • 特点都是由键决定的:无序、不重复、无索引
  • HashMap跟HashSet底层原理是一模一样的,都是哈希表结构
  • 依赖hashcode方法和equals方法保证键的唯一
  • 如果键存储的是自定义对象,需要重写hashcode和Wequals方法
  • 如果值存储自定义对象,不需要重写hashCode和equals方法

2.2 HashMap案例

案例1
  • 案例需求

    • 需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。
      存储三个键值对元素,并遍历
      要求:同姓名,同年龄认为是同一个学生
  • 代码实现

    学生类

    package com.itheima.a02mayhashmap;
    
    import java.util.Objects;
    
    public class Student {
        private String name;
      private int age;
        //getter、setter和构造函数
       
        @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 int hashCode() {
          return Objects.hash(name, age);
        }
    
        public String toString() {
          return "Student{name = " + name + ", age = " + age + "}";
        }
    }
    
    
  
  测试类
  
  ```java
  /*
     核心点:
       HashMap的键位置如果存储的是自定义对象,需要重写hashCode和equals方法。
    */
     //1.创建HashMap的对象
     HashMap<Student,String> hm = new HashMap<>();
   //2.创建三个学生对象
     Student s1 = new Student("zhangsan",23);
     Student s2 = new Student("lisi",24);
     Student s3 = new Student("wangwu",25);
     Student s4 = new Student("wangwu",25);
     //3.添加元素
     hm.put(s1,"江苏");
     hm.put(s2,"浙江");
     hm.put(s3,"福建");
   hm.put(s4,"山东");
     //4.遍历集合-方式1
   Set<Student> keys = hm.keySet();
     for (Student key : keys) {
         String value = hm.get(key);
         System.out.println(key + "=" + value);
     }
     System.out.println("--------------------------");
   //4.遍历集合-方式2
     Set<Map.Entry<Student, String>> entries = hm.entrySet();
     for (Map.Entry<Student, String> entry : entries) {
         Student key = entry.getKey();
         String value = entry.getValue();
         System.out.println(key + "=" + value);
   }
     System.out.println("--------------------------");
     hm.forEach((student, s)-> System.out.println(student + "=" +  s));
  

在这里插入图片描述

案例2
  • 案例需求
    • 某个班级80名学生,现在需要组成秋游活动,
      班长提供了四个景点依次是(A、B、C、D),
      每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。
  • 代码实现
   //1.需要先让同学们投票
   //定义一个数组,存储4个景点
   String[] arr = {"A","B","C","D"};
   //利用随机数模拟80个同学的投票,并把投票的结果存储起来
   ArrayList<String> list = new ArrayList<>();
   Random r = new Random();
   for (int i = 0; i < 80; i++) {
       int index = r.nextInt(arr.length);
       list.add(arr[index]);
   }
   //2.如果要统计的东西比较多,不方便使用计数器思想
   //我们可以定义map集合,利用集合进行统计。
   HashMap<String,Integer> hm = new HashMap<>();
   for (String name : list) {
       //判断当前的景点在map集合当中是否存在
       if(hm.containsKey(name)){
           //存在
           //先获取当前景点已经被投票的次数
           int count = hm.get(name);
           //表示当前景点又被投了一次
           count++;
           //把新的次数再次添加到集合当中
           hm.put(name,count);
       }else{
           //不存在
           hm.put(name,1);
       }
   }
   System.out.println(hm);
   //3.求最大值
   int max = 0;
   Set<Map.Entry<String, Integer>> entries = hm.entrySet();
   for (Map.Entry<String, Integer> entry : entries) {
       int count = entry.getValue();
       if(count > max){
           max = count;
       }
   }
   System.out.println(max);
   //4.判断哪个景点的次数跟最大值一样,如果一样,打印出来
   for (Map.Entry<String, Integer> entry : entries) {
       int count = entry.getValue();
       if(count == max){
           System.out.println(entry.getKey());
       }
   }

2.3 LinkedHashMap

LinkedHashMap是HashMap的子类

  • 由键决定:有序、不重复、无索引。

  • 这里的有序指的是保证存储和取出的元素顺序一致

  • 原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。

    在这里插入图片描述

   /*
      LinkedHashMap:
          由键决定:
              有序、不重复、无索引。
          有序:
              保证存储和取出的顺序一致
          原理:
              底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
    */
   //1.创建集合
   LinkedHashMap<String,Integer> lhm = new LinkedHashMap<>();
   //2.添加元素
   lhm.put("c",789);
   lhm.put("b",456);
   lhm.put("a",123);
   lhm.put("a",111);
   //3.打印集合
   System.out.println(lhm);

3. TreeMap集合

3.1 概述

  • TreeMap跟TreeSet底层原理一样,都是红黑树结构的。

  • 由键决定特性:不重复、无索引、可排序

  • 可排序:对键进行排序

  • 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则

    代码书写两种排序规则

    • 实现Comparable接口,指定比较规则。
    • 创建集合时传递Comparator比较器对象,指定比较规则。

3.2TreeMap集合应用案例

案例一

键:整数表示id
值:字符串表示商品名称
要求1:按照id的升序排列

要求2:按照id的降序排列

  //1.创建集合对象
  //Integer Double 默认情况下都是按照升序排列的
  //String 按照字母再ASCII码表中对应的数字升序进行排列
  //abcdefg ...
  TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {
      @Override
      public int compare(Integer o1, Integer o2) {
          //o1:当前要添加的元素
          //o2:表示已经在红黑树中存在的元素
          return o2 - o1;
      }
  });
  //2.添加元素
  tm.put(5,"可恰可乐");
  tm.put(4,"雷碧");
  tm.put(3,"九个核桃");
  tm.put(2,"康帅傅");
  tm.put(1,"粤利粤");
  //3.打印集合
  System.out.println(tm);
案例二
  • 案例需求

    • 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
    • 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
  • 代码实现

    学生类

    package com.itheima.a04mytreemap;
    
    public class Student implements Comparable<Student>{
      private String name;
        private int age;
        //setter和getter还有构造函数
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                  ", age=" + age +
                    '}';
        }
    
      //按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。
        //this:表示当前要添加的元素
        //o:表示已经在红黑树中存在的元素//返回值:
        负数:表示当前要添加的元素是小的,存左边
      // 正数:表示当前要添加的元素是大的,存右边
        // 0:表示当前要添加的元素已经存在,舍弃
    
        @Override
      public int compareTo(Student o) {
            int i=this.getAge()-o.getAge();
            i=i==0?this.getName().compareTo(o.getName()):i;
            return i;
      }
    }
    
    

    测试类

      //1.创建集合
        TreeMap<Student,String> tm = new TreeMap<>();
        //2.创建三个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        //3.添加元素
        tm.put(s1,"江苏");
        tm.put(s2,"天津");
        tm.put(s3,"北京");
        tm.forEach(
              (Student key, String value)->{
                    System.out.println(key + "---" + value);
              }
        );
    
;