Java类集框架-Map

Map集合

概述

特点

基本使用

基本功能(定义在Map接口中的共性方法)

代码实现

获取功能

Map集合的遍历(2种方式)

(1)第一种——获取所有的键,get到所有的值

代码实现

(2)第二种——获取到所有的键值对对象,每一个对象打印键、值

代码实现

HashMap集合

概述和特点

HashMap集合应用案例

案例需求

代码实现

运行结果

forEach()源码解析

TreeMap集合

概述与特点

TreeMap集合应用案例

案例需求

代码实现


Map集合

之前学习的单列集合

而双列集合如下图所示:

在Map中,键值对是一一对应的关系。

把一对键值对视为键值对对象,在Java中,叫做Entry

概述

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

特点

  • 双列集合,一个键对应一个值

  • 不可以重复,值可以重复

基本使用

public class MapDemo01 {
    public static void main(String[] args) {
        //创建集合对象
        Map<String,String> map = new HashMap<String,String>();

        //V put(K key, V value) 将指定的值与该映射中的指定键相关联
        // 学号 -- 姓名
        map.put("201810066","林青霞");
        map.put("201810044","张曼玉");
        map.put("201810022","王祖贤");
        map.put("201810056","柳岩");

        //输出集合对象
        System.out.println(map);
        //{201810056=柳岩, 201810066=林青霞, 201810044=张曼玉, 201810022=王祖贤}
    }
}

基本功能(定义在Map接口中的共性方法)

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

代码实现

public class Demo{
    public static void main(String[] args) {
        Map<String,String> mp = new HashMap<>();
        //(1) V put(K key,V value)添加元素
        //如果键不存在,就直接添加到集合中
        //如果键存在,那么会覆盖原先的值,并把原先的值返回
        mp.put("1001","小明");
        mp.put("1002","小强");
        mp.put("1003","小张");
        mp.put("1004","小李");
        System.out.println(mp);
        //{1004=小李, 1003=小张, 1002=小强, 1001=小明}

        String s1 = mp.put("1004","aaa");
        System.out.println(s1);
        //小李
        System.out.println(mp);
        //{1004=aaa, 1003=小张, 1002=小强, 1001=小明}

        //(2) V remove(Object key)根据键删除键值对元素
        String s2 = mp.remove("1004");
        System.out.println(s2);
        //aaa
        System.out.println(mp);
        //{1003=小张, 1002=小强, 1001=小明}

        //(3) boolean containsKey(Object key)判断集合是否包含指定的键
        System.out.println(mp.containsKey("1001"));
        //true
        System.out.println(mp.containsKey("2002"));
        //false

        //(4) boolean containsValue(Object value)判断集合是否包含指定的值
        System.out.println(mp.containsValue("小张"));
        //true

        //(5) int size()集合的长度,也就是集合中键值对的个数
        System.out.println(mp.size());
        //3

        //(6) boolean isEmpty()判断集合是否为空
        System.out.println(mp.isEmpty());
        //false

        //(7) void clear()移除所有的键值对元素
        mp.clear();
        System.out.println(mp);
        //{}  空!
    }
}

获取功能

方法名说明
V get(Object key)根据键获取值
Set<K> keySet()获取所有键的集合
Collection<V> values()获取所有值的集合
Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合

Map集合的遍历(2种方式)

(1)第一种——获取所有的键,get到所有的值

详细步骤如下

代码实现

public class Demo {
    public static void main(String[] args) {
        //创建集合并添加元素
        Map<String,String> map = new HashMap<>();
        map.put("1号丈夫","1号妻子");
        map.put("2号丈夫","2号妻子");
        map.put("3号丈夫","3号妻子");
        map.put("4号丈夫","4号妻子");
        map.put("5号丈夫","5号妻子");

        //获取所有的键
        Set<String> keys = map.keySet();
        for (String key : keys) {
            //通过每一个key,来获取到对应的值
            String value = map.get(key);
            System.out.println(key + "-" + value);
            //1号丈夫-1号妻子
            //2号丈夫-2号妻子
            //5号丈夫-5号妻子
            //4号丈夫-4号妻子
            //3号丈夫-3号妻子
        }
    }
}

(2)第二种——获取到所有的键值对对象,每一个对象打印键、值

详细步骤如下

代码实现

public class Demo {
    public static void main(String[] args) {
        //创建集合并添加元素
        Map<String,String> map = new HashMap<>();
        map.put("1号丈夫","1号妻子");
        map.put("2号丈夫","2号妻子");
        map.put("3号丈夫","3号妻子");
        map.put("4号丈夫","4号妻子");
        map.put("5号丈夫","5号妻子");

        //首先要获取到所有的键值对对象
        //Set集合里面装的是键值对对象(Entry对象)
        //而Entry里面装的是键和值
        Set<Map.Entry<String,String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            //得到每一个键值对对象
            System.out.println(entry.getKey() + "-" + entry.getValue());
            //1号丈夫-1号妻子
            //2号丈夫-2号妻子
            //5号丈夫-5号妻子
            //4号丈夫-4号妻子
            //3号丈夫-3号妻子
        }
    }
}

HashMap集合

概述和特点

  • HashMap底层是哈希表结构的

  • 依赖hashCode方法和equals方法保证的唯一

  • 如果要存储的是自定义对象,需要重写hashCode和equals方法

HashMap集合应用案例

案例需求

创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。

要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象

代码实现

由于此处自定义对象,所以我们必须要重写hashCode()与equals方法。

public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

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

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

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

使用3种方式遍历HashMap

public class Demo {
    public static void main(String[] args) {
        HashMap<Student, String> hm = new HashMap<>();

        Student s1 = new Student("小明", 12);
        Student s2 = new Student("小张", 22);
        Student s3 = new Student("小李", 32);
        Student s4 = new Student("小红", 15);

        hm.put(s1, "南京");
        hm.put(s2, "北京");
        hm.put(s3, "上海");
        hm.put(s4, "广州");

        //(1) 第一种遍历:先找到所有的键,再通过每一个键找到对应的值
        Set<Student> keys = hm.keySet();
        for (Student key1 : keys) {
            String value1 = hm.get(key1);
            System.out.println(key1 + "--" + value1);
        }
        System.out.println("======================");

        //(2) 第二种遍历:先获取到所有的键值对对象,再获取里面的每一个键和每一个值
        Set<Map.Entry<Student, String>> entries = hm.entrySet();
        for (Map.Entry<Student, String> entry : entries) {
            Student key2 = entry.getKey();
            String value2 = entry.getValue();
            System.out.println(key2 + "--" + value2);
        }
        System.out.println("======================");

        //(3) 第三种遍历:使用Map种的forEach方法
        hm.forEach(
                (Student key3, String value3) -> {
                    System.out.println(key3 + "--" + value3);
                }
        );
    }
}

运行结果

Student{name='小张', age=22}--北京
Student{name='小李', age=32}--上海
Student{name='小红', age=15}--广州
Student{name='小明', age=12}--南京
======================
Student{name='小张', age=22}--北京
Student{name='小李', age=32}--上海
Student{name='小红', age=15}--广州
Student{name='小明', age=12}--南京
======================
Student{name='小张', age=22}--北京
Student{name='小李', age=32}--上海
Student{name='小红', age=15}--广州
Student{name='小明', age=12}--南京

Process finished with exit code 0

forEach()源码解析

我们可以选中HashMap然后Ctrl+B

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

然后再进入Map接口里面,再Ctrl+F12,搜索出forEach()方法

default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
        // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
        action.accept(k, v);
    }
}

可以发现action是BiConsumer类型的,而BiConsumer只是一个接口,里面只有一个抽象方法accept

public interface BiConsumer<T, U> {
    void accept(T t, U u);
    ......
}

具体过程如下 

总的来说就是: 

forEach()方法底层进行了一次遍历,依次得到每一个键和值,然后通过action.accept(k,v),将键和值又传递给,我们自己写的lambda表达式中,来执行对应的逻辑。

TreeMap集合

概述与特点

  • TreeMap底层是红黑树结构

  • 依赖自然排序或者比较器排序,对进行排序

  • 如果存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

TreeMap集合应用案例

案例需求

  • 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历

  • 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序

代码实现

实现方式(一)实现Comparable接口

public class Demo {
    public static void main(String[] args) {
        TreeMap<Student,String> tm = new TreeMap<>();

        Student s1 = new Student("小黑",23);
        Student s2 = new Student("小红",32);
        Student s3 = new Student("小白",13);
        Student s4 = new Student("小李",34);

        tm.put(s1,"南京");
        tm.put(s2,"上海");
        tm.put(s3,"广州");
        tm.put(s4,"江苏");

        tm.forEach(
                (Student key,String value) -> {
                    System.out.println(key + "---" + value);
                }
        );
        //Student{name='小白', age=13}---广州
        //Student{name='小黑', age=23}---南京
        //Student{name='小红', age=32}---上海
        //Student{name='小李', age=34}---江苏
    }
}
public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student() {
    }

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

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

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

    @Override
    public int compareTo(Student o) {
        //按照年龄
        int result = this.getAge() - o.getAge();
        //按照姓名
        result = result == 0 ? this.getName().compareTo(o.getName()) : result;
        return result;
    }
}

实现方式(二)比较器排序规则

public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Demo {
    public static void main(String[] args) {
        TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int result = o1.getAge() - o2.getAge();
                result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                return result;
            }
        });

        Student s1 = new Student("小黑",23);
        Student s2 = new Student("小红",32);
        Student s3 = new Student("小白",13);
        Student s4 = new Student("小李",34);

        tm.put(s1,"南京");
        tm.put(s2,"上海");
        tm.put(s3,"广州");
        tm.put(s4,"江苏");

        tm.forEach(
                (Student key,String value) -> {
                    System.out.println(key + "---" + value);
                }
        );
        //Student{name='小白', age=13}---广州
        //Student{name='小黑', age=23}---南京
        //Student{name='小红', age=32}---上海
        //Student{name='小李', age=34}---江苏
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金鳞踏雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值