10-集合3-Map、HashMap、TreeMap、可变参数、Of初始化集合

1.Map集合

单列集合一次只能存入一个数据,而双列集合一次可以存入两个(一对)数据
(键key,值value) : 称为”键值对“或”键值对对象“、java中叫"Entry"对象

在这里插入图片描述

1.1Map集合概述和特点【理解】

  • Map集合概述

    interface Map<K,V>  K:键的类型;V:值的类型
    
  • Map集合的特点
    双列集合,一个键对应一个值
    键不可以重复,值可以重复

在这里插入图片描述

  • Map集合的基本使用
    public static void main(String[] args) {
        //<学号,姓名>
        Map<String,String > map=new HashMap<>();

        //新的collection分支的公共方法了
        //没有add,插入双列值得put
        map.put("whu1001","小米");
        map.put("whu1002","小美");
        map.put("whu1003","大胖");
        map.put("whu1002","小美1");//key重复的会被舍弃 保留最后一个

        System.out.println(map);//"{whu1002=小美1, whu1001=小米, whu1003=大胖}"
    }

1.2Map集合的基本功能【应用】 (★所有map共有的一些方法★)

Map接口里的方法,HashMap和TreeMap都会有的

  • 方法介绍

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

//如果要添加的键不存在,那么会把键值对都添加到集合中
//如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。

    public static void main(String[] args) {
        Map<String,String > map=new HashMap<>();
        // V   put(K key,V   value)            | 添加元素
        //如果要添加的键不存在,那么会把键值对都添加到集合中
        //如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
        map.put("whu1001","小米");
        map.put("whu1002","小美");
        map.put("whu1003","大胖");
        map.put("whu1004","小黑");
        map.put("whu1005","大帅1");
        String s = map.put("whu1005", "大帅");//返回已经存在key对应的value
        System.out.println(s);//"大帅1"
        System.out.println(map);
        //输出: {whu1002=小美, whu1001=小米, whu1004=小黑, whu1003=大胖, whu1005=大帅}
        //无序 key不重复 键值对形式
    }
  • 示例代码2: V remove(Object key)
    public static void main(String[] args) {
        Map<String,String > map=new HashMap<>();
        map.put("whu1001","小米");
        map.put("whu1002","小美");
        map.put("whu1003","大胖");
        map.put("whu1004","小黑");
        map.put("whu1005","大帅");

        // V remove(Object key) | 根据键删除键值对元素
        String s = map.remove("whu1001");
        System.out.println(s);//"小米"
        //小米被删除了
        System.out.println(map);//"{whu1002=小美, whu1004=小黑, whu1003=大胖, whu1005=大帅}"
    }
  • 示例代码3: void clear()
    public static void main(String[] args) {
        Map<String,String > map=new HashMap<>();
        map.put("whu1001","小米");
        map.put("whu1002","小美");
        map.put("whu1003","大胖");
        map.put("whu1004","小黑");
        map.put("whu1005","大帅");

        // void clear()                      | 移除所有的键值对元素
        map.clear();//真的清空了所有键值对
        System.out.println(map);//"{}"
    }
  • 示例代码4: boolean containsKey(Object key) && boolean containsValue(Object value)
    public static void main(String[] args) {
        Map<String,String > map=new HashMap<>();
        map.put("whu1001","小米");
        map.put("whu1002","小美");
        map.put("whu1003","大胖");
        map.put("whu1004","小黑");
        map.put("whu1005","大帅");

        // boolean containsKey(Object key)     | 判断集合是否包含指定的键
        boolean b1 = map.containsKey("whu1001");
        boolean b2 = map.containsKey("whu1007");
        System.out.println(b1);//true
        System.out.println(b2);//false
        // boolean containsValue(Object value) | 判断集合是否包含指定的值
        boolean res1 = map.containsValue("小米");
        boolean res2 = map.containsValue("大米");
        System.out.println(res1);//true
        System.out.println(res2);//false
    }
  • 示例代码5: int size() && boolean isEmpty()
    public static void main(String[] args) {
        Map<String,String > map=new HashMap<>();
        map.put("whu1001","小米");
        map.put("whu1002","小美");
        map.put("whu1003","大胖");
        map.put("whu1004","小黑");
        map.put("whu1005","大帅");

        // int size()  | 集合的长度,也就是集合中键值对的个数
        int size = map.size();
        System.out.println(size);//5
         
        // boolean isEmpty() | 判断集合是否为空
        boolean b = map.isEmpty();
        System.out.println(b);//false

        map.clear();
        System.out.println(map.isEmpty());//true
        System.out.println(map.size());//0
    }

1.3Map集合的获取功能【应用】(还是顶层接口,也就是所有map都有的方法)

  • 方法介绍

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

简单查下API,就能知道Map.Entry的所有方法
在这里插入图片描述

  • 示例代码
    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号妻子");

        System.out.println("=============所有键==============");
        //获取所有键
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key);
        }

        //获取所有值
        System.out.println("=============所有值==============");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }
        //获取所有键值对
        System.out.println("==============所有键值对==============");
         
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry);
            //entry.getKey();//都有
            //entry.getValue();//都有
        }
    }

在这里插入图片描述

1.4Map集合的遍历(方式1:遍历keySet,再一个一个获取值)【应用】

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 把所有的丈夫给集中起来
      • 遍历丈夫的集合,获取到每一个丈夫
      • 根据丈夫去找对应的妻子
  • 步骤分析

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

    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) {
            System.out.println(key+" "+map.get(key));
        }
    }

在这里插入图片描述

1.5Map集合的遍历(方式2:直接获取键值对集合entrySet())【应用】

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 获取所有结婚证的集合
      • 遍历结婚证的集合,得到每一个结婚证
      • 根据结婚证获取丈夫和妻子
  • 步骤分析

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

    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对象),泛型就是Map.Entry(Entry是Map的内部接口)
        //Entry里存储的键值对,其两个泛型分别是键类型、值类型
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"--"+value);
        }
    }

在这里插入图片描述

2.HashMap集合(底层哈希表)

Map的一个实现类 没有额外要学习的方法,直接使用Map里的方法就行了
底层也是哈希表
jdk8之前 数组+链表
jdk8以后 数组+链表|红黑树
(底层和HashSet一样 或者不如说HashSet直接底层就是用到HashMap )

2.1HashMap集合概述和特点【理解】

  • HashMap底层是哈希表结构的
  • 依赖hashCode方法和equals方法保证的唯一
  • 如果键要存储的是自定义对象,需要重写hashCode和equals方法

2.2HashMap集合应用案例【应用】

  • 案例需求

    • 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
    • 要求保证的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
  • 代码实现

Student.java

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

    // 空参构造
    
    // 全参构造

    // 所有get/set

    //tostring


    //重写(其实是自动生成) equals和hashCode方法  【HashSet和HashMap存储自定义对象时 必须的步骤】
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name) &&
                Objects.equals(age, student.age);
    }

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

测试

    public static void main(String[] args) {
        //<学生,籍贯>
        HashMap<Student,String> hm=new HashMap<>();
        Student s1 = new Student("xiaohei", 23);
        Student s2 = new Student("dapang", 22);
        Student s3 = new Student("xiaomei", 22);

        hm.put(s1,"苏");
        hm.put(s2,"京");
        hm.put(s3,"津");

        //三种方式遍历

        //1.先获取所有键keySet()  再遍历
        Set<Student> keys = hm.keySet();
        for (Student key : keys) {
            String s = hm.get(key);
            System.out.println(key+"\t"+s);
        }
        System.out.println("==================================");
         
        //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+"\t"+value);
        }
        System.out.println("==================================");

        //3.Map.forEach(lambda表达式) ★
        //参数(键,值)  方法体:想干啥 直接写
        hm.forEach((Student key,String value)->{System.out.println(key+"\t"+value);});
    }

在这里插入图片描述

新增一种遍历方式,forEach

查看源码,就是用for帮你遍历了

HashMap的
在这里插入图片描述
Map的
在这里插入图片描述
在这里插入图片描述

3.TreeMap集合(底层红黑树 自动排序 查找也飞快)

同样没有新方法要学习,直接用Map接口中的方法即可

3.1TreeMap集合概述和特点【理解】

  • TreeMap底层是红黑树结构
  • 依赖自然排序或者比较器排序,对键进行排序
  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

每个键值对打包在一起作为一个结点 但是比较大小时只关心,不关心值
每次put都在构建(插入)红黑树

3.2TreeMap集合应用案例一【应用】

  • 案例需求

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

    学生类

public class Student implements Comparable<Student>{
    //用到了Tree 红黑树 必须给出compareTo比较规则  否则遍历就会报错
    private String name;
    private Integer age;

    // 空参构造
    
    // 全参构造

    // 所有get/set

    // tostring

    //用到了Tree 红黑树 必须给出compareTo比较规则  否则遍历就会报错
    @Override
    public int compareTo(Student o) {
        //一级排序年龄升序  二级排序姓名序
        int result = this.getAge() - o.getAge();
        if(result==0) result=this.getName().compareTo(o.getName());
        return result;
    }
}

Test1.java

public class Test1 {
    public static void main(String[] args) {
        TreeMap<Student,String> tm=new TreeMap<>();
        Student s1 = new Student("xiaohei", 23);
        Student s2 = new Student("dapang", 22);
        Student s3 = new Student("xiaomei", 22);
        Student s4 = new Student("tianhe", 19);
        Student s5 = new Student("xiaomei", 22);//重复的自动不要

        tm.put(s1,"苏");
        tm.put(s2,"京");
        tm.put(s3,"津");
        tm.put(s4,"皖");
        tm.put(s5,"浙");

        //使用就很方便了 (主要时验证下 有没有根据年龄排序)
        Set<Student> keys = tm.keySet();
        for (Student key : keys) {
            String s = tm.get(key);
            System.out.println(key+"\t"+s);
        }
    }
}

在这里插入图片描述

  • 代码实现2
    student.java
public class Student implements Comparable<Student>{
    //用到了Tree 红黑树 必须给出compareTo比较规则  否则遍历就会报错
    private String name;
    private Integer age;

    // 空参构造
    
    // 全参构造

    // 所有get/set

    // tostring
}

Test2.java

    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();
                if(result==0) result=o1.getName().compareTo(o2.getName());
                return -result;//加个负号变降序
            }
        });
        Student s1 = new Student("xiaohei", 23);
        Student s2 = new Student("dapang", 22);
        Student s3 = new Student("xiaomei", 22);
        Student s4 = new Student("tianhe", 19);
        Student s5 = new Student("xiaomei", 22);//重复的自动不要

        tm.put(s1,"苏");
        tm.put(s2,"京");
        tm.put(s3,"津");
        tm.put(s4,"皖");
        tm.put(s5,"浙");

        //使用就很方便了 (主要时验证下 有没有根据年龄排序)
        tm.forEach((Student key, String value)->{System.out.println(key+"\t"+value);});
    }

在这里插入图片描述

3.3TreeMap集合应用案例二【应用】

  • 案例需求

    • 给定一个字符串,要求统计字符串中每个字符出现的次数。
    • 举例: 给定字符串是“aababcabcdabcde”,在控制台输出: “a(5)b(4)c(3)d(2)e(1)”

看成普通Map就行了 map[‘a’]='a’出现次数 (其实是map.get(‘a’)=='a’出现次数)
用treeMap,自动按key排序了

  • 代码实现
    public static void main(String[] args) {
        String s="aababcabcdabcde";
        TreeMap<Character,Integer> tm=new TreeMap<>();
        for(int i=0;i<s.length();i++){
            Character c=s.charAt(i);
            if(tm.containsKey(c)){
                tm.put(c,tm.get(c)+1);//次数+1  直接重复复制就会覆盖(插入没有HashMap快)
            }else {
                tm.put(c,1);
            }
        }
        
        tm.forEach((Character key,Integer value)->{System.out.print(key+" ("+value+") ");});
    }

4.可变参数

4.1可变参数【应用】

  • 可变参数介绍

    • 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
    • 方法的参数类型已经确定,个数不确定,我们可以使用可变参数
  • 可变参数定义格式

    修饰符 返回值类型 方法名(数据类型… 变量名) {  }
    

    例如:

    int sum(int... a) {}
    
  • 可变参数的注意事项

    • 这里的变量其实是一个数组
    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后(轮到可变参数接收时,给多少要多少,只能放在最后)
  • 可变参数的基本使用

定义一个方法,求N个整数的和

jdk5之前

/**
 * 定义一个方法,求N个数的和
 */
public class MyVariableParameter2 {
    public static void main(String[] args) {
        //jdk5之前 自己用数组实现
        int[] arr={1,2,3,4,5};//还得提起申请数组,好麻烦
        int sum1=getSum(arr);
        System.out.println(sum1);//15
    }
    private static int getSum(int[] arr) {
        int sum=0;
        for (int i : arr) sum+=i;
        return sum;
    }
}

jdk5之后

/**
 * 定义一个方法,求N个数的和
 */
public class MyVariableParameter2 {
    public static void main(String[] args) {
        //jdk5之后直接用可变参数即可 ★
        int sum2=getSum2(1,2,3,4,5);//可以直接写任意多个参数
        System.out.println(sum2);//15
		System.out.println(getSum2(7,8,9,10));//34
    }
    private static int getSum2(int... arr) {
        int sum=0;
        for (int i : arr) sum+=i;
        return sum;
    }
}

4.2创建不可变集合【理解】(JDK9引入)

  • 方法介绍

    • 在List、Set、Map接口中,都存在of方法(形参都是可变参数),可以创建一个不可变的集合
      • 这个集合不能添加,不能删除,不能修改
      • 但是可以结合集合的带参构造,实现集合的批量添加
    • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
      • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中

在这里插入图片描述

  • 示例代码1:List.of(…)

static List of(E…elements) 创建一个具有指定元素的List集合对象

    public static void main(String[] args) {
        // static <E>  List<E>  of(E…elements)  创建一个具有指定元素的List集合对象      

        //jdk9引入的新方法 jdk8以及8以下都执行不了
        List<String> list=List.of("a","b","c","d");
        System.out.println(list);//输出: [a,b,c,d]
        //list.add("Q");//报错: 不准添加
        //list.remove("a");//报错: 不准删除
        //list.set(0,"A");//报错: 不准修改
        System.out.println(list);

        //使用: 集合的批量添加。
        //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
        //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。(其实是利用了List的有参构造)
        ArrayList<String> list3=new ArrayList<>(List.of("a","b","c","d"));
        //初始化时不需要慢慢调用list.add("XX")方法了 多方便
        System.out.println(list3);//输出: [a,b,c,d]
    }
  • 示例代码2:Set.of(…)

static Set of(E…elements) 创建一个具有指定元素的Set集合对象

    public static void main(String[] args) {    	
        //static <E>  Set<E>  of(E…elements)    创建一个具有指定元素的Set集合对象
        
        //传递的参数当中,不能存在重复的元素。
        Set<String> set = Set.of("a", "b", "c", "d");
        //Set<String> set = Set.of("a", "b", "c", "d","a");//报错 不能有重复
        System.out.println(set);//输出: [a,b,c,d]
    }
  • 示例代码3:Map.of(…)

static <K , V> Map<K,V> of(E…elements) 创建一个具有指定元素的Map集合对象

    public static void main(String[] args) {   
        //static <K , V>   Map<K,V>  of(E…elements)
        // 创建一个具有指定元素的Map集合对象
        Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津");
        System.out.println(map);//输出: {lisi=北京, wangwu=天津, zhangsan=江苏}
    }

Map.ofEntries( Map.entry(“zhangsan”, “江苏”), Map.entry(“lisi”, “北京”));

Map<String, String> map = Map.ofEntries(//同样jdk9才有
                Map.entry("zhangsan", "江苏"),
                Map.entry("lisi", "北京"));//先封装两个entry对象,再将entry对象放到map中
System.out.println(map);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值