当前位置:   article > 正文

Java开发从入门到精通(二十):Java的面向对象编程OOP:Map集合框架

Java开发从入门到精通(二十):Java的面向对象编程OOP:Map集合框架

(一)Java的集合进阶

1.1 集合体系结构

为了应对不同的场景需要,所以提供很多集合,总体来说分成单列集合和双列集合
在这里插入图片描述

1.2 Map集合

1.2.1 认识Map集合

  • Map集合称为双列集合,格式:{key1=value1,key2=value2,key3=value3,….,一次需要存一对数据做为一个元素
  • Map集合的每个元素“kev=value”称为一个键值对/键值对对象/一个Entry对象,Map集合也被叫做“键值对集合”
  • Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值
    在这里插入图片描述

1.2.2 Map集合在什么业务场景下使用

在这里插入图片描述

1.2.3 Map集合体系

在这里插入图片描述

注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的

  • HashMap(由键决定特点):无序、不重复、无索引;(用的最多)
  • LinkedHashMap (由键决定特点):由键决定的特点:有序、不重复、无索引。
  • TreeMap (由键决定特点):按照大小默认升序排序、不重复、无索引。
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class MapTest {
    public static void main(String[] args) {

        Map<String,Integer> map =new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        map.put("手表",100);
        map.put("手表",220);  //后面重复的数据会覆盖前面的数据(键决定的)
        map.put("手机",3);
        map.put("Java",3);
        map.put(null,null);
        System.out.println(map);

        Map<String,Integer> map2 =new LinkedHashMap<>();//一行经典代码。按照键 //有序,不重复,无索引。
        map2.put("手表",100);
        map2.put("手表",220);
        map2.put("手机",3);
        map2.put("Java",3);
        map2.put(null,null);
        System.out.println(map2);

        Map<Integer,String>map1=new TreeMap<>();// 可排序,不重复,无索引
        map1.put(23,"Java");
        map1.put(23,"MySQL");
        map1.put(19,"李四");
        map1.put(20,"王五");
        System.out.println(map1);


    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

1.2.3 Map集合的方法

为什么要先学习Map的常用方法?
Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的,Map的常用方法如下
在这里插入图片描述

import java.util.*;

public class MapTest {
    public static void main(String[] args) {

        Map<String, Integer> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        map.put("手表", 100);
        map.put("手表", 220);  //后面重复的数据会覆盖前面的数据(键决定的)
        map.put("手机", 3);
        map.put("Java", 3);
        map.put(null, null);
        System.out.println(map);

        //2.public int size():获取集合的大小
        System.out.println(map.size());

        // 3、public void clear():清空集合
        //map.clear();System.out.println(map);

        // 4.public boolean isEmpty():判断集合是否为空,为空返回true,反之!
        System.out.println(map.isEmpty());

        //5.public v get(object key)根据键获取对应值
        int v1 = map.get("手表");
        System.out.println(v1);
        System.out.println(map.get("手机"));//3
        System.out.println(map.get("张三"));// nulL

        //6.public Vremove(object key):根据键删除整个元素(删除键会返回键的值)
        System.out.println(map.remove("手表"));
        System.out.println(map);

        //7.public boolean containsKey(0bject key):判断是否包含某个键 ,包含返回true,反之
        System.out.println(map.containsKey("手表"));// false
        System.out.println(map.containsKey("手机"));//true
        System.out.println(map.containsKey("java"));//false
        System.out.println(map.containsKey("Java"));//true


        //8.public boolean containsValue(object value): 判断是否包含某个值。
        System.out.println(map.containsValue(2));//true
        System.out.println(map.containsValue("2"));// false

        //9.public Set<K> keySet(): 获取Map集合的全部键
        Set<String> keys = map.keySet();
        System.out.println(keys);

        //10.public Collection<V>values();获取Map集合的全部值,
        Collection<Integer> values = map.values();
        System.out.println(values);

        // 11.把其他Map集合的数据倒入到自己集合中来。(拓展)
        Map<String, Integer> map1 = new HashMap<>();
        map1.put("java1", 10);
        map1.put("java2", 20);
        Map<String, Integer> map2 = new HashMap<>();
        map2.put("java3", 10);
        map2.put("java2", 222);
        map1.putAll(map2);// putAl:把map2集合中的元素全部倒入一份到map1集合中去。
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

1.2.4 Map集合的遍历

Map集合遍历的三种方式
在这里插入图片描述

1.2.4.1 Map集合遍历:键找值

Map的方法
在这里插入图片描述

import java.util.*;
public class MapTest {
    public static void main(String[] args) {

        Map<String, Double> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        map.put("蜘蛛精",162.5);
        map.put("蜘蛛精",169.8);
        map.put("紫霞",165.8);
        map.put("至尊宝",169.5);
        map.put("牛魔王",183.6);
        System.out.println(map);
        // map = {蜘蛛精=169.8,牛魔王=183.6,至尊宝=169.5,紫霞=165.8}

        //1、获取Map集合的全部键
        Set<String> keys = map.keySet();
        System.out.println(keys);
        // 2、遍历全部的键,根据键获取其对应的值
        for(String key :keys) {
            // 根据键获取对应的值
            double value = map.get(key);
            System.out.println(key + "=====>" + value);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

遍历Map集合方式一:键找值流程
在这里插入图片描述

1.2.4.2 Map集合遍历:键值对
  • 遍历如果使用增强for的话无法指明元素类型,所以不行

在这里插入图片描述

  • 可以使用map提供的方法entrySet方法,使用getkey获取key getValue获取值

在这里插入图片描述

import java.util.*;

public class MapTest {
    public static void main(String[] args) {

        Map<String, Double> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        map.put("蜘蛛精",162.5);
        map.put("蜘蛛精",169.8);
        map.put("紫霞",165.8);
        map.put("至尊宝",169.5);
        map.put("牛魔王",183.6);
        System.out.println(map);
        // map = {蜘蛛精=169.8,牛魔王=183.6,至尊宝=169.5,紫霞=165.8}
        // entries =[(蜘蛛精=169.8),(牛魔王=183.6),(至宝=169.5),(紫霞=165.8)]
        //              entry

        //1、调用Map集合提供entrySet方法,把Map集合转换成键值对类型的Set集合
        Set<Map.Entry<String,Double>> entries = map.entrySet();
        for(Map.Entry<String,Double>entry:entries) {
            String key = entry.getKey();
            double value = entry.getValue();
            System.out.println(key +"---->"+ value);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

1.2.4.3 Map集合遍历:Lambda

需要用到Map的如下方法:
在这里插入图片描述

public class MapTest {
    public static void main(String[] args) {

        Map<String, Double> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        map.put("蜘蛛精",162.5);
        map.put("蜘蛛精",169.8);
        map.put("紫霞",165.8);
        map.put("至尊宝",169.5);
        map.put("牛魔王",183.6);
        System.out.println(map);
        // map = {蜘蛛精=169.8,牛魔王=183.6,至尊宝=169.5,紫霞=165.8}
        // entries =[(蜘蛛精=169.8),(牛魔王=183.6),(至宝=169.5),(紫霞=165.8)]
        //              entry

        map.forEach((k,v)->{
            System.out.println(k +"--->" + v);
        });

        map.forEach(new BiConsumer<String,Double>() {
            @Override
            public void accept(String k, Double v) {
                System.out.println(k + "---->" + v);
            }
        });

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

lambda表达式的优化

        map.forEach(new BiConsumer<String,Double>() {
            @Override
            public void accept(String k, Double v) {
                System.out.println(k + "---->" + v);
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

优化成这个样子

 map.forEach((k,v)->{
            System.out.println(k +"--->" + v);
        });
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.2.4.4 Map集合的案例-统计投票人数

需求:

  • 某个班级80名学生,现在需要组织秋游活动,班长提供了四个景点依次是(A、B、C、D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多。

分析

  • 将80个学生选择的数据拿到程序中去,「A,A,B,A,B,C,D,…]
  • 准备一个Map集合用于存储统计的结果,Map<String,Integer>,键是景点,值代表投票数量
  • 遍历80个学生选择的景点,每遍历一个景点,就看Map集合中是否存在该景点,不存在存入“景点=1存在则其对应值+1,
import java.util.*;
import java.util.function.BiConsumer;

public class MapTest {
    public static void main(String[] args) {
        // 1、把80个学生选择的景点数据拿到程序中来。
        List<String> data = new ArrayList<>();
        String[] selects ={"A","B","C","D"};
        Random r=new Random();
        for(int i = 1; i <= 80; i++) {
            // 每次模拟一个学生选择一个景点,存入到集合中去。
            int index = r.nextInt(4);//0 1 2 3
            data.add(selects[index]);
        }
        System.out.println(data);

        // 2、开始统计每个景点的投票人数
        // 准备一个Map集合用于统计最终的结果
        Map<String,Integer> result =new HashMap<>();
        // 3、开始遍历80个景点数据
        for(String s:data){
            // 问间Map集合中是否存在该景点
            if(result.containsKey(s)){
                // 说明这个景点之前统计过。其值+1.存入到Map集合中去
                result.put(s,result.get(s)+1);
            }else {
                result.put(s,1);
            }
        }
        // 说明这个景点是第一次统计,存入"景点=1
        System.out.println(result);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
1.2.4.5 HashMap底层原理

HashMap(由键决定特点):无序、不重复、无索引;(用的最多》

  • HashMap跟Hashset的底层原理是一一样的,都是基于哈希表实现的。
  • 实际上:原来学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据不要值数据而已
    在这里插入图片描述
    哈希表
  • JDK8之前,哈希表=数组+链表
  • JDK8开始,哈希表=数组+链表+红黑树
  • 哈希表是一种增删改查数据,性能都较好的数据结构。

用键的hash值来计算的元素的位置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

HashMap底层是基于哈希表实现的

  • HashMap集合是一种增删改查数据,”性能都较好的集合

  • 但是它是无序,不能重复,没有索引支持的(由键决定特点)

  • HashMap的键依赖hashcode方法和equals方法保证键的唯一

  • 如果键存储的是自定义类型的对象,可以通过重写hashcode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的。

import java.util.*;
import java.util.function.BiConsumer;

public class MapTest {
    public static void main(String[] args) {
        Map<Student,String> map =new HashMap<>();
        map.put(new Student("蜘蛛精",25,168.5),"盘丝洞");
        map.put(new Student( "蜘蛛精",25,168.5),"水帘洞");
        map.put(new Student( "至尊宝",23,163.5),"水帘洞");
        map.put(new Student( "牛魔王",28,183.5),"牛头山");
        System.out.println(map);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这里可以看出蜘蛛精的键是重复的

{Student{name='蜘蛛精', age=25, height=168.5}=水帘洞, Student{name='牛魔王', age=28, height=183.5}=牛头山, Student{name='蜘蛛精', age=25, height=168.5}=盘丝洞, Student{name='至尊宝', age=23, height=163.5}=水帘洞}
  • 1

通过重写hashcode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能自动去重

package com.qianxin.jihekuangjia;

import java.util.Objects;

public class Student implements Comparable<Student>{
    private String name;
    private int age;
    private double height;

    @Override
    public int compareTo(Student o) {

        // 如果认为左边对象大于右边对象返回正整数
        // 如果认为左边对象小于右边对象返回负整数
        // 如果认为左边对象等于右边对象返回0
        // 需求:按照年龄升序排序、

        return this.age-o.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 && Double.compare(height, student.height) == 0 && Objects.equals(name, student.name);
    }

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

    public Student() {
    }

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

    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;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

保证键的唯一

{Student{name='至尊宝', age=23, height=163.5}=水帘洞, Student{name='牛魔王', age=28, height=183.5}=牛头山, Student{name='蜘蛛精', age=25, height=168.5}=水帘洞}
  • 1
1.2.4.6 LinkedHashMap底层原理

LinkedHashMap (由键决定特点):由键决定的特点:有序、不重复、无索引。

  • 底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。
  • 实际上:原来学习的LinkedHashset集合的底层原理就是LinkedHashMap。

键值会合并成一个entry对象
在这里插入图片描述
通过其中键的hash值来算出在集合中的位置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2.4.7 TreeMap底层原理

TreeMap (由键决定特点):按照大小默认升序排序、不重复、无索引。

特点:不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)
原理:TreeMap跟TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。

TreeMap集合同样也支持两种方式来指定排序规则

方法一:让类实现Comparable接口,重写比较规则。
使用TreeMap会对下面的集合进行排序,但是键是自定义对象,无法排序,所以报错

public class MapTest {
    public static void main(String[] args) {
        //Map<String, Integer> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        Map<Student,String> map =new TreeMap<>();
        map.put(new Student("蜘蛛精",25,168.5),"盘丝洞");
        map.put(new Student( "蜘蛛精",25,168.5),"水帘洞");
        map.put(new Student( "至尊宝",23,163.5),"水帘洞");
        map.put(new Student( "牛魔王",28,183.5),"牛头山");
        System.out.println(map);

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
如果我们想要实现TreeMap的自定义排序,可以使用Comparable接口 重写CompareTo方法来实现自定义排序

import java.util.Objects;
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    private double height;

    @Override
    public int compareTo(Student o) {

        // 如果认为左边对象大于右边对象返回正整数
        // 如果认为左边对象小于右边对象返回负整数
        // 如果认为左边对象等于右边对象返回0
        // 需求:按照年龄升序排序、

        return this.age-o.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 && Double.compare(height, student.height) == 0 && Objects.equals(name, student.name);
    }

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

    public Student() {
    }

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

    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;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

没有报错,且实现按照年龄升序排列

{Student{name='至尊宝', age=23, height=163.5}=水帘洞, Student{name='蜘蛛精', age=25, height=168.5}=水帘洞, Student{name='牛魔王', age=28, height=183.5}=牛头山}
  • 1

方法二TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。

创建Comparator比较器对象,实现按照升高降序排列

import java.util.*;
import java.util.function.BiConsumer;

public class MapTest {
    public static void main(String[] args) {
        //Map<String, Integer> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        Map<Student,String> map =new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o2.getHeight(),o1.getHeight());
            }
        });
        map.put(new Student("蜘蛛精",25,168.5),"盘丝洞");
        map.put(new Student( "蜘蛛精",25,168.5),"水帘洞");
        map.put(new Student( "至尊宝",23,163.5),"水帘洞");
        map.put(new Student( "牛魔王",28,183.5),"牛头山");
        System.out.println(map);

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
{Student{name='牛魔王', age=28, height=183.5}=牛头山, Student{name='蜘蛛精', age=25, height=168.5}=水帘洞, Student{name='至尊宝', age=23, height=163.5}=水帘洞}
  • 1

简写Comparator比较器代码

import java.util.*;
import java.util.function.BiConsumer;

public class MapTest {
    public static void main(String[] args) {
        //Map<String, Integer> map = new HashMap<>();//一行经典代码。按照键 无序,不重复,无索引。
        Map<Student,String> map =new TreeMap<>((o1,o2) ->Double.compare(o2.getHeight(),o1.getHeight()));


        map.put(new Student("蜘蛛精",25,168.5),"盘丝洞");
        map.put(new Student( "蜘蛛精",25,168.5),"水帘洞");
        map.put(new Student( "至尊宝",23,163.5),"水帘洞");
        map.put(new Student( "牛魔王",28,183.5),"牛头山");
        System.out.println(map);

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/461383
推荐阅读
相关标签
  

闽ICP备14008679号