Java SE 学习笔记(十)—— 集合(3)

1 Map 集合

1.1 Map 集合概述


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

  • 使用最多的 Map 集合是 HashMap
  • 重点掌握 HashMapLinkedHashMapHashTableTreeMap

单列集合一次存一个元素,双列集合一次存两个元素,一个键(不可以重复)对应一个值(可以重复)。(键+值)这个整体我们称之为键值对键值对对象,在Java中叫做Entry对象

Map 是一种双列集合,也称为 键值对集合,其键无序、不重复,其值不做要求,可以重复,Map 集合的特点都是由键决定的,后面重复的键对应的值会覆盖前面重复键的值。其键值都可以为 null

  • HashMap:元素按照键是无序、不重复、无索引、值不做要求(与Map体系一致)
  • LinkedHashMap:元素按照键是 有序、不重复、无索引、值不做要求
  • TreeMap:元素按照键是 排序、不重复、无索引、值不做要求

Map 集合格式:

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

Map集合是一个接口,不能直接创建对象,创建 Map 集合的对象有两种方式:

  • 多态
  • 具体的实现类 HashMap

基本用法:

public static void main(String[] args) {
	Map<String,String> map = new HashMap<>();

	//map.add();
	map.put("itheima001","小智");
	map.put("itheima002","小美");
	map.put("itheima003","大胖");

	System.out.println(map);
}

1.2 Map 常用方法


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

在这里插入图片描述

🙋举个栗子:

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

public class Test {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("001","小智");
        map.put("002","小美");
        map.put("003","大胖");
        map.put("004","小黑");
        map.put("005","大师");
		
		// 拓展,合并其他Map集合
		 Map<String,String> map2 = new HashMap<>();
		 map2.put("111","hu");
		 map2.put("222","long");
		 // 把map2的元素拷贝到map1中
		 map.putAll(map2);


        //method1(map);
        //method2(map);
        //method3(map);
        //method4(map);
        //method5(map);
        //method6(map);
        //method7(map);

    }

    private static void method7(Map<String, String> map) {
        //        int size()              集合的长度,也就是集合中键值对的个数
        int size = map.size();
        System.out.println(size);
    }

    private static void method6(Map<String, String> map) {
        //        boolean isEmpty()       判断集合是否为空
        boolean empty1 = map.isEmpty();
        System.out.println(empty1);//false

        map.clear();
        boolean empty2 = map.isEmpty();
        System.out.println(empty2);//true
    }

    private static void method5(Map<String, String> map) {
        //        boolean containsValue(Object value) 判断集合是否包含指定的值
        boolean result1 = map.containsValue("aaa");
        boolean result2 = map.containsValue("小智");
        System.out.println(result1);
        System.out.println(result2);
    }

    private static void method4(Map<String, String> map) {
        //        boolean containsKey(Object key) 判断集合是否包含指定的键
        boolean result1 = map.containsKey("001");
        boolean result2 = map.containsKey("006");
        System.out.println(result1);
        System.out.println(result2);
    }

    private static void method3(Map<String, String> map) {
        //        void clear()            移除所有的键值对元素
        map.clear();
        System.out.println(map);
    }

    private static void method2(Map<String, String> map) {
        //        V remove(Object key)    根据键删除键值对元素
        String s = map.remove("itheima001");
        System.out.println(s);
        System.out.println(map);
    }

    private static void method1(Map<String, String> map) {
        //        V put(K key,V value)    添加元素
        //如果要添加的键不存在,那么会把键值对都添加到集合中
        //如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
        String s = map.put("001", "aaa");
        System.out.println(s);
        System.out.println(map);
    }
}

1.3 Map 的遍历


在这里插入图片描述

❗️注意:

  • 使用get 根据键获取值,当键不存在的时候会返回null

1️⃣ 遍历方式1:键找值

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();
	//遍历Set集合得到每一个键
	for (String key : keys) {
		//通过每一个键key,来获取到对应的值
		String value = map.get(key);
		System.out.println(key + "---" + value);
	}
}

2️⃣ 遍历方式2:键值对

在这里插入图片描述

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) {
		//得到每一个键值对对象
		String key = entry.getKey();
		String value = entry.getValue();
		System.out.println(key + "---" + value);
	}
}

3️⃣ 遍历方式3:lambda 表达式

在这里插入图片描述

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号妻子");

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

2 HashMap 类


HashMap 类

  • HashMap 底层是哈希表结构的,与HashSet底层原理是一样的,只是HashMap 的每个元素包含两个值而已
  • 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
  • 依赖 hashCode 方法和 equals方法保证 的唯一
    • 如果 要存储的是自定义对象,需要重写 hashCodeequals 方法(hashCode不同时,则必为不同对象;hashCode相同时,根据 equlas 方法不能判断是否为同一对象)

实际上,Set系列集合的底层就是Map实现的,只是Set集合的数据只要键数据,不要值数据而已

🙋举个栗子:

案例需求:

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

学生类

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;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

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

测试类

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

public class Test {
    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);
        Student s4 = new Student("xiaomei", 22);

        hm.put(s1, "江苏");
        hm.put(s2, "北京");
        hm.put(s3, "天津");
        hm.put(s4, "天津");

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

        System.out.println("===================================");

        //第二种:先获取到所有的键值对对象。再获取到里面的每一个键和每一个值
        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( //forEach方法在Map接口的两个实现类中都是可以实现的
                (Student key, String value) -> {
                    System.out.println(key + "----" + value);
                }
        );
    }
}

3 LinkedHashMap 类


LinkedHashMap

  • 由键决定:有序、不重复、无索引
    • 这里的有序指的是保证存储和取出的元素顺序一致
  • 底层原理依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序

🙋举个栗子:

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

public class Test {
    public static void main(String[] args) {
        Map<String,Integer> map=new LinkedHashMap<>();
        map.put("哈哈",1);
        map.put("嘿嘿",1);
        map.put("嘻嘻",3);
        map.put("呵呵",2);
        map.put(null,null);
        System.out.println(map); // {哈哈=1, 嘿嘿=1, 嘻嘻=3, 呵呵=2, null=null}
    }
}

4 TreeMap 类

  • TreeMap 底层是红黑树结构
  • 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
  • TreeMap 也是一定要排序的,依赖自然排序或者比较器排序,对 进行排序
    • 如果 存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
    • 由于 TreeMap元素不能重复,排序的时候只要大小一样,就认为重复,后面的重复数据会覆盖前面的

🙋举个栗子:

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

1️⃣ 实现Comparable接口

学生类

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 = o.getAge() - this.getAge(); // 从大到小排序,若是从小到大则需要为:int result = this.getAge()- o.getAge();
        //次要条件,按照姓名排序。
        result = result == 0 ? o.getName().compareTo(this.getName()) : result;
        return result;
    }
}

测试类

public static void main(String[] args) {
    // 创建TreeMap集合对象
    TreeMap<Student,String> tm = new TreeMap<>();

    // 创建学生对象
    Student s1 = new Student("xiaohei",23);
    Student s2 = new Student("dapang",22);
    Student s3 = new Student("xiaomei",22);

    // 将学生对象添加到TreeMap集合中
    tm.put(s1,"江苏");
    tm.put(s2,"北京");
    tm.put(s3,"天津");

    // 遍历TreeMap集合,打印每个学生的信息
    tm.forEach(
            (Student key, String value)->{
                System.out.println(key + "---" + value);
            }
    );
}

2️⃣ 创建TreeMap对象时候给出比较器排序规则

学生类

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 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("xiaohei",23);
	Student s2 = new Student("dapang",22);
	Student s3 = new Student("xiaomei",22);

	tm.put(s1,"江苏");
	tm.put(s2,"北京");
	tm.put(s3,"天津");

	tm.forEach(
			(Student key, String value)->{
				System.out.println(key + "---" + value);
			}
	);
}

5 Properties


Properties 集合是一个Map体系的集合类,其属性列表中的每个键及其对应的值都是一个字符串

创建Properties对象的时候不写泛型

5.1 Properties基本使用


public static void main(String[] args) {
	Properties prop = new Properties();
	//增
	prop.put("小龙女","尹志平");
	prop.put("郭襄","杨过");
	prop.put("黄蓉","欧阳克");
	System.out.println(prop);

	//删
	//prop.remove("郭襄");
	//System.out.println(prop);

	//改
	//put --- 如果键不存在,那么就添加,如果键存在,那么就覆盖.
	prop.put("小龙女","杨过");
	System.out.println(prop);
	//查

	//Object value = prop.get("黄蓉");
	//System.out.println(value);

	//遍历
	Set<Object> keys = prop.keySet();
	for (Object key : keys) {
		Object value = prop.get(key);
		System.out.println(key + "=" + value);
	}

	System.out.println("========================");

	//装的是所有的键值对对象.
	Set<Map.Entry<Object, Object>> entries = prop.entrySet();
	for (Map.Entry<Object, Object> entry : entries) {
		Object key = entry.getKey();
		Object value = entry.getValue();
		System.out.println(key + "=" + value);
	}
}

5.2 Properties特有方法


在这里插入图片描述

public static void main(String[] args) {
	//Object setProperty​(String key, String value) --- put
				//设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
	Properties prop = new Properties();
	prop.setProperty("江苏","南京");
	prop.setProperty("安徽","南京");
	prop.setProperty("山东","济南");

	System.out.println(prop);
	//String getProperty​(String key)  --- get
				//使用此属性列表中指定的键搜索属性

	String value = prop.getProperty("江苏");
	System.out.println(value);


	//Set<String> stringPropertyNames​()  --- keySet
				//从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串

	Set<String> keys = prop.stringPropertyNames();
	for (String key : keys) {
		String value = prop.getProperty(key);
		System.out.println(key + "=" + value);
	}
}

6 可变参数与不可变集合

6.1 可变参数


可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

可变参数的作用:传输参数非常灵活、方便

  • 可以不传输参数
  • 可以传1个或多个参数
  • 可以传输一个数组

当方法的参数类型已经确定,个数不确定,我们可以使用可变参数

可变参数定义格式

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

🙋举个栗子:

需求:定义一个方法求N个数的和

import java.util.Arrays;

public class Demo {
    public static void main(String[] args) {
        sum();
        sum(10);
        sum(10, 20);
        sum(new int[]{1, 2, 3, 4, 5});
        
/*       元素个数:0
        元素内容:[]
        元素个数:1
        元素内容:[10]
        元素个数:2
        元素内容:[10, 20]
        元素个数:5
        元素内容:[1, 2, 3, 4, 5]*/
    }

    public static void sum(int... nums) {
        // 可变参数本质上就是一个数组
        System.out.println("元素个数:"+nums.length);
        System.out.println("元素内容:"+ Arrays.toString(nums));
    }
}

❗️注意:

  • 可变参数在方法内部本质上就是一个数组
  • 一个形参列表中可变参数只有一个
  • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

6.2 不可变集合


不可变集合,即不可以被修改的集合,集合的数据项在创建的时候提供,并且在整个生命周期中都不改变,否则报错

为什么要创建不可变集合?

  • 如果某个数据不能被修改,把它防御性地拷贝到不可变集合红是个很好的实践
  • 或者当集合对象被不可信的库调用时,不可变形式是安全的

如何创建不可变集合?

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

在这里插入图片描述

🙋举个栗子:

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

	//method1();
	//method2();
	//method3();
	//method4();
}

private static void method4() {
	Map<String, String> map = Map.ofEntries(
			Map.entry("zhangsan", "江苏"),
			Map.entry("lisi", "北京"));
	System.out.println(map); // {lisi=北京, zhangsan=江苏}
}

private static void method3() {
	Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津");
	System.out.println(map); // {lisi=北京, zhangsan=江苏, wangwu=天津}
}

private static void method2() {
	//传递的参数当中,不能存在重复的元素。
	Set<String> set = Set.of("a", "b", "c", "d","a");
	System.out.println(set); // 会报错
}

private static void method1() {
	List<String> list = List.of("a", "b", "c", "d");
	System.out.println(list); // [a, b, c, d]

	//集合的批量添加。
	//首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
	//再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
	ArrayList<String> list3 = new ArrayList<>(List.of("a", "b", "c", "d"));
	System.out.println(list3);
}

7 集合工具类Collections


java.utils.Collections:是集合工具类,Collections并不属于集合,而是用来操作集合的工具类

💞 Collections 常用的 API

在这里插入图片描述

Collections 排序相关 API

  • 使用范围:只能对于 List 集合的排序

在这里插入图片描述

示例代码:

学生类

public class Student {
    private String names;
    private int age;
    private double height;

    public Student() {
    }

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

    public String getNames() {
        return names;
    }

    public void setNames(String names) {
        this.names = names;
    }

    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{" +
                "names='" + names + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

测试类

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        // 一个一个添加元素
//        names.add("高辛玖瑶");
//        names.add("涂山璟");
//        names.add("九命相柳");
//        names.add("西炎玱玹");
//        names.add("赤水丰隆");
//        System.out.println(names);

        // 批量添加元素
        Collections.addAll(names, "高辛玖瑶", "涂山璟", "九命相柳", "西炎玱玹", "赤水丰隆");
        System.out.println(names); // [高辛玖瑶, 涂山璟, 九命相柳, 西炎玱玹, 赤水丰隆]

        // 打乱集合顺序
        Collections.shuffle(names);
        System.out.println(names); // [涂山璟, 高辛玖瑶, 赤水丰隆, 九命相柳, 西炎玱玹]

        // 将集合中的元素按照默认规则排序(排值特性的元素)
        List<Integer> nums = new ArrayList<>();
        Collections.addAll(nums, 10, 5, 6, 8, 4, 1);
        Collections.sort(nums);
        System.out.println(nums); // [1, 4, 5, 6, 8, 10]

        // 对自定义对象排序(也可以在自定义对象类中重写比较规则)
        List<Student> stus = new ArrayList<>();
        stus.add(new Student("小胖",20,173.1));
        stus.add(new Student("小美",18,159.9));
        stus.add(new Student("小黑",21,183.5));

        Collections.sort(stus, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
//                return o1.getAge()- o2.getAge(); // 按年龄升序排序
                return Double.compare(o1.getHeight(),o2.getHeight()); // 按身高升序排序
            }
        });
        System.out.println(stus);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值