22--Map集合

1、Map集合

· 现实生活与开发中,我们常会看到这样的一类集合:用户ID与账户信息、学生姓名与考试成绩、IP地址与主机名等,这种一一对应的关系,就称作映射。Java提供了专门的集合框架用来存储这种映射关系的对象,即java.util.Map接口。

1.1 Map接口概述

Map与Collection并列存在。用于保存具有映射关系的数据:key-value

  • Collection集合称为单列集合,元素是孤立存在的(理解为单身)。
  • Map集合称为双列集合,元素是成对存在的(理解为夫妻)。

Map 中的 key 和 value 都可以是任何引用类型的数据。但常用String类作为Map的“键”。

Map接口的常用实现类:HashMapLinkedHashMapTreeMap和`Properties。其中,HashMap是 Map 接口使用频率最高的实现类。

22--Map集合_第1张图片

1.2 Map中key-value特点

这里主要以HashMap为例说明。HashMap中存储的key、value的特点如下:

22--Map集合_第2张图片

Map 中的 key用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法

22--Map集合_第3张图片

key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value,不同key对应的value可以重复。value所在的类要重写equals()方法。

key和value构成一个entry。所有的entry彼此之间是无序的、不可重复的

1.3 Map与Collection集合区别

Collection集合

        单列集合,一次只能添加一个元素

        有的是有索引,有的没有索引

        有的集合可以存储重复的元素,有的则不可以

        有的元素是无序的,有的是有序的

Map集合

        Map集合是双列集合,由Key和Value组成

        Key是不允许重复的,Value是允许重复

        Key允许存null值的,但是只能存储唯一的一个

1.4 Map接口中常用的方法

1.4.1 添加、修改操作

public Object put(Object key,Object value)

        将指定key-value添加到(或修改)当前map对象中

public void putAll(Map m)

        将m中的所有key-value对存放到当前map中

package com.suyv.map;

import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 10:26
*@Description: Map接口的添加和修改方法
*/
public class MapDemo01 {

    // put(Object key,Object value)
    @Test
    public void Test01(){
        Map map = new HashMap();
        // 添加数据
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}

        // 修改数据
        map.put("1","红楼梦");
        System.out.println(map);        // {1=红楼梦, 2=西游记}

    }

    // putAll(Map m)        添加数据
    @Test
    public void Test02(){
        Map map1 = new HashMap();
        // 添加数据
        map1.put("1","三国演义");
        map1.put("2","西游记");

        System.out.println(map1);        // {1=三国演义, 2=西游记}


        Map map2 = new HashMap();
        // 添加数据
        map2.put("3","水浒传");
        map2.put("4","红楼梦");
        System.out.println(map2);       // {3=水浒传, 4=红楼梦}

        map1.putAll(map2);
        System.out.println(map1);       // {1=三国演义, 2=西游记, 3=水浒传, 4=红楼梦}
    }

    // putAll(Map m)        修改数据
    @Test
    public void Test03(){
        Map map1 = new HashMap();
        // 添加数据
        map1.put("1","三国演义");
        map1.put("2","西游记");

        System.out.println(map1);        // {1=三国演义, 2=西游记}


        Map map2 = new HashMap();
        // 添加数据
        map2.put("1","水浒传");
        map2.put("2","红楼梦");
        System.out.println(map2);       // {1=水浒传, 2=红楼梦}

        map1.putAll(map2);
        System.out.println(map1);       // {1=水浒传, 2=红楼梦}
    }
}

1.4.2 删除操作:

public Object remove(Object key)

        移除指定key的key-value对,并返回value

public void clear()

        清空当前map中的所有数据

package com.suyv.map;

import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 10:37
*@Description: Map接口的删除方法
*/
public class MapDemo02 {

    /*public Object remove(Object key)
    移除指定key的key-value对,并返回value
    public void clear()
    清空当前map中的所有数据*/

    // remove(Object key)
    // 移除指定key的key-value对,并返回value
    @Test
    public void Test01(){
        Map map = new HashMap();
        // 添加数据
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        System.out.println(map.remove("1"));    // 三国演义
        System.out.println(map);        // {2=西游记}
    }

    // clear()
    // 清空当前map中的所有数据
    @Test
    public void Test02(){
        Map map = new HashMap();
        // 添加数据
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        map.clear();
        System.out.println(map);        // {}
    }
}

1.4.3 元素查询的操作:

public Object get(Object key)

        获取指定key对应的value

public boolean containsKey(Object key)

        是否包含指定的key

public boolean containsValue(Object value)

        是否包含指定的value

public int size()

        返回map中key-value对的个数

public boolean isEmpty()

        判断当前map是否为空

public boolean equals(Object obj)

        判断当前map和参数对象obj是否相等

package com.suyv.map;

import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 10:43
*@Description: Map集合中元素查询方法
*/
public class MapDemo03 {

    // get(Object key)
    // 获取指定key对应的value
    @Test
    public void Test01(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        System.out.println(map.get("1"));    // 三国演义
    }

    // containsKey(Object key)
    // 是否包含指定的key
    @Test
    public void Test02(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        System.out.println(map.containsKey("1"));    // true
        System.out.println(map.containsKey("3"));    // false
    }

    // containsValue(Object value)
    // 是否包含指定的value
    @Test
    public void Test03(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        System.out.println(map.containsValue("三国演义"));    // true
        System.out.println(map.containsKey("红楼梦"));    // false
    }

    // size()
    // 返回map中key-value对的个数
    @Test
    public void Test04(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        System.out.println(map.size()); // 2
    }

    // isEmpty()
    // 判断当前map是否为空
    @Test
    public void Test05(){
        Map map = new HashMap();

        System.out.println(map.isEmpty());  // true

        map.put("1","三国演义");
        map.put("2","西游记");

        System.out.println(map);        // {1=三国演义, 2=西游记}
        System.out.println(map.isEmpty()); // false
    }

    // equals(Object obj)
    // 判断当前map和参数对象obj是否相等
    @Test
    public void Test06(){
        Map map1 = new HashMap();
        map1.put("1","三国演义");
        map1.put("2","西游记");
        System.out.println(map1);        // {1=三国演义, 2=西游记}


        Map map2 = new HashMap();
        map2.put("1","三国演义");
        map2.put("2","西游记");
        System.out.println(map2);       // {1=三国演义, 2=西游记}

        System.out.println(map1.equals(map2));  // true

        map2.remove("1");
        System.out.println(map1.equals(map2));  // false
    }
}

1.5 Map集合的遍历

Map集合遍历的方法:

public Set keySet()

        返回所有key构成的Set集合

public Collection values()

        返回所有value构成的Collection集合

public Set entrySet()

        返回所有key-value对构成的Set集合

package com.suyv.map;

import org.junit.Test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 10:54
*@Description: Map集合的遍历
*/
public class MapDemo04 {
    // public Set keySet()
    // 返回所有key构成的Set集合
    @Test
    public void Test01(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");
        map.put("3","水浒传");
        map.put("4","红楼梦");
        System.out.println(map);       // {1=三国演义, 2=西游记, 3=水浒传, 4=红楼梦}

        Set keySet = map.keySet();
        for (Object obj : keySet) {
            System.out.println(obj);    // 1    2   3   4
        }
    }

    // public Collection values()
    // 返回所有value构成的Collection集合
    @Test
    public void Test02(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");
        map.put("3","水浒传");
        map.put("4","红楼梦");
        System.out.println(map);       // {1=三国演义, 2=西游记, 3=水浒传, 4=红楼梦}

        Collection values = map.values();
        for (Object obj : values) {
            System.out.println(obj);    // 三国演义 西游记 水浒传 红楼梦
        }
    }

    // public Set entrySet()
    // 返回所有key-value对构成的Set集合
    @Test
    public void Test03(){
        Map map = new HashMap();
        map.put("1","三国演义");
        map.put("2","西游记");
        map.put("3","水浒传");
        map.put("4","红楼梦");
        System.out.println(map);       // {1=三国演义, 2=西游记, 3=水浒传, 4=红楼梦}

        Set entrySet = map.entrySet();
        for (Object obj : entrySet) {
            System.out.println(obj);    // 1=三国演义   2=西游记   3=水浒传   4=红楼梦
        }
    }

}

1.6 Map存储自定义类型元素

需求

每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。

要求: 学生姓名相同并且年龄相同视为同一名学生

编写学生类

package com.suyv.map;

import java.util.Objects;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 11:35
*@Description: 学生实体类Student
*/
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 +
        '}';
    }

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

编写测试类

package com.suyv.map;

import org.junit.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 11:37
*@Description: 自定义实体类的测试类
*/
public class MapDemo05 {

    @Test
    public void Test01(){
        //1、创建Map集合对象
        Map map = new HashMap();

        //2、添加元素
        map.put(new Student("lisi",28), "上海");
        map.put(new Student("wangwu",22), "北京");
        map.put(new Student("zhaoliu",24), "成都");
        map.put(new Student("zhouqi",25), "广州");
        map.put(new Student("wangwu",22), "南京");

        //3、取出元素、键找值方式
        Set keySet = map.keySet();
        for(Student key: keySet){
            String value = map.get(key);
            System.out.println(key.toString()+"....."+value);
            // Student{name='zhaoliu', age=24}.....成都
            // Student{name='lisi', age=28}.....上海
            // Student{name='wangwu', age=22}.....南京
            // Student{name='zhouqi', age=25}.....广州
        }
    }
}

当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须重写对象的hashCode和equals方法。

如果要保证map中存放的key和取出的顺序一致,可以使用java.util.LinkedHashMap集合来存放。

2、Map的主要实现类:HashMap

2.1 HashMap概述

HashMap是 Map 接口使用频率最高的实现类。

HashMap是线程不安全的。允许添加 null 键和 null 值。

存储数据采用的哈希表结构,底层使用数组+单向链表+红黑树进行key-value数据的存储。与HashSet一样,元素的存取顺序不能保证一致。

HashMap 判断两个key相等的标准是:两个 key 的hashCode值相等,通过 equals() 方法返回 true。

HashMap 判断两个value相等的标准是:两个 value 通过 equals() 方法返回 true。

2.2 练习

2.2.1 练习--二级联动

将省份和城市的名称保存在集合中,当用户选择省份以后,二级联动,显示对应省份的地级市供用户选择。

效果演示:

22--Map集合_第4张图片

package com.suyv.hashMap;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 12:08
*@Description: HashMap练习实现二级联动
*/
public class HashMapDemo01 {
    public static void main(String[] args) {
        Map model = new HashMap();

        model.put("北京", new String[] {"北京"});
        model.put("上海", new String[] {"上海"});
        model.put("天津", new String[] {"天津"});
        model.put("重庆", new String[] {"重庆"});
        model.put("黑龙江", new String[] {"哈尔滨","齐齐哈尔","牡丹江","大庆","伊春","双鸭山","绥化"});
        model.put("吉林", new String[] {"长春","延边","吉林","白山","白城","四平","松原"});
        model.put("河北", new String[] {"石家庄","张家口","邯郸","邢台","唐山","保定","秦皇岛"});
        model.put("河南", new String[] {"郑州","开封","洛阳","周口","新乡","驻马店","安阳"});

        Set keySet = model.keySet();
        for(Object s : keySet) {
            System.out.print(s + "\t");
        }
        System.out.println();
        System.out.println("请选择你所在的省份:");
        Scanner scan = new Scanner(System.in);
        String province = scan.next();

        String[] citys = (String[])model.get(province);
        for(String city : citys) {
            System.out.print(city + "\t");
        }
        System.out.println();
        System.out.println("请选择你所在的城市:");
        String city = scan.next();

        System.out.println("信息登记完毕");
    }
}

3、Map实现类之二:LinkedHashMap

LinkedHashMap 是 HashMap 的子类

存储数据采用的哈希表结构+链表结构,在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的先后顺序,可以保证遍历元素时,与添加的顺序一致。

通过哈希表结构可以保证键的唯一、不重复,需要键所在类重写hashCode()方法、equals()方法。

总结:有序,key唯一

package com.suyv.hashMap;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 12:15
*@Description: LinkedHashMap类的使用
*/
public class LinkedHashMapDemo {
    public static void main(String[] args) {
        LinkedHashMap map = new LinkedHashMap();

        map.put("王五", 13000.0);
        map.put("张三", 10000.0);
        //key相同,新的value会覆盖原来的value
        //因为String重写了hashCode和equals方法

        map.put("张三", 12000.0);
        map.put("李四", 14000.0);
        //HashMap支持key和value为null值

        String name = null;
        Double salary = null;
        map.put(name, salary);

        Set entrySet = map.entrySet();
        for (Object obj : entrySet) {
            Map.Entry entry = (Map.Entry)obj;
            System.out.println(entry);
            // 王五=13000.0
            // 张三=12000.0
            // 李四=14000.0
            // null=null
        }
    }
}

4、Map实现类之三:TreeMap

TreeMap存储 key-value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 key-value 对处于有序状态。

TreeSet底层使用红黑树结构存储数据

TreeMap 的 Key 的排序:

        自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException

        定制排序:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口

TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0

package com.suyv.hashMap;

import org.junit.Test;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeMap;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 12:21
*@Description: TreeMap的使用
*/
public class TreeMapDemo {

    // 自然排序的使用
    @Test
    public void Test01(){
        TreeMap map = new TreeMap();

        map.put("CC",45);
        map.put("MM",78);
        map.put("DD",56);
        map.put("GG",89);
        map.put("JJ",99);

        Set entrySet = map.entrySet();
        for(Object entry : entrySet){
            System.out.println(entry);
            // CC=45
            // DD=56
            // GG=89
            // JJ=99
            // MM=78
        }
    }

    // 自然排序--自定义类
    @Test
    public void Test02(){
        TreeMap map = new TreeMap();

        map.put(new User("Tom",12),67);
        map.put(new User("Rose",23),"87");
        map.put(new User("Jerry",2),88);
        map.put(new User("Eric",18),45);
        map.put(new User("Tommy",44),77);
        map.put(new User("Jim",23),88);
        map.put(new User("Maria",18),34);

        Set entrySet = map.entrySet();
        for(Object entry : entrySet){
            System.out.println(entry);
            // User{name='Jerry', age=2}=88
            // User{name='Tom', age=12}=67
            // User{name='Maria', age=18}=34
            // User{name='Eric', age=18}=45
            // User{name='Rose', age=23}=87
            // User{name='Jim', age=23}=88
            // User{name='Tommy', age=44}=77
        }
    }

    // 定制排序的使用
    @Test
    public void Test03(){

        //按照User的姓名的从小到大的顺序排列
        TreeMap map = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof User && o2 instanceof User){
                    User u1 = (User)o1;
                    User u2 = (User)o2;

                    return u1.getName().compareTo(u2.getName());
                }
                throw new RuntimeException("输入的类型不匹配");
            }
        });

        map.put(new User("Tom",12),67);
        map.put(new User("Rose",23),"87");
        map.put(new User("Jerry",2),88);
        map.put(new User("Eric",18),45);
        map.put(new User("Tommy",44),77);
        map.put(new User("Jim",23),88);
        map.put(new User("Maria",18),34);

        Set entrySet = map.entrySet();
        for(Object entry : entrySet){
            System.out.println(entry);
            // User{name='Eric', age=18}=45
            // User{name='Jerry', age=2}=88
            // User{name='Jim', age=23}=88
            // User{name='Maria', age=18}=34
            // User{name='Rose', age=23}=87
            // User{name='Tom', age=12}=67
            // User{name='Tommy', age=44}=77
        }
    }

}

// 定义实体类
class User implements Comparable{
    private String name;
    private int age;

    public User() {
    }

    public User(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 "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    // 按照age从小到大的顺序排列,如果age相同,则按照name从大到小的顺序排列
    @Override
    public int compareTo(Object o) {
        if(this == o){
            return 0;
        }

        if(o instanceof User){
            User user = (User)o;
            int value = this.age - user.age;
            if(value != 0){
                return value;
            }
            return -this.name.compareTo(user.name);
        }
        throw new RuntimeException("输入的类型不匹配");
    }
}

5、Map实现类之四:Hashtable

Hashtable是Map接口的古老实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的

Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构(数组+单向链表),查询速度快。

与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序

Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。

与HashMap不同,Hashtable 不允许使用 null 作为 key 或 value。

面试题:Hashtable和HashMap的区别

HashMap:底层是一个哈希表(jdk7:数组+链表;jdk8:数组+链表+红黑树),是一个线程不安全的集合,执行效率高

Hashtable:底层也是一个哈希表(数组+链表),是一个线程安全的集合,执行效率低

HashMap集合:可以存储null的键、null的值

Hashtable集合,不能存储null的键、null的值

Hashtable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。所以HashMap是Map的主要实现类,Hashtable是Map的古老实现类。

Hashtable的子类Properties(配置文件)依然活跃在历史舞台

Properties集合是一个唯一和IO流相结合的集合

6、Map实现类之五:Properties

Properties 类是 Hashtable 的子类,该对象用于处理属性文件

由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型

存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法

package com.suyv.hashMap;

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

/**
*@Author: 憨憨浩浩
*@CreateTime: 2023-12-18 13:05
*@Description: Properties类的使用
*/
public class PropertiesDemo {

    @Test
    public void Test01() {
        Properties properties = System.getProperties();
        String fileEncoding = properties.getProperty("file.encoding");//当前源文件字符编码
        System.out.println("fileEncoding = " + fileEncoding);
    }

    @Test
    public void Test02() {
        Properties properties = new Properties();
        properties.setProperty("user","songhk");
        properties.setProperty("password","123456");
        System.out.println(properties);
    }

    @Test
    public void Test03() throws IOException {
        // File file = new File("jdbc.properties");
        // System.out.println(file.getAbsoluteFile());

        Properties pros = new Properties();
        pros.load(new FileInputStream("jdbc.properties"));
        String user = pros.getProperty("user");
        System.out.println(user);
    }
}

你可能感兴趣的:(JavaSE学习记录,java,开发语言)