Java基础学习笔记(十四)—— 集合(2)

news2025/1/18 21:04:19

集合

  • 1 Set 集合
    • 1.1 Set 集合概述
    • 1.2 Set 集合的使用
  • 2 TreeSet 类
    • 2.1 TreeSet 类概述
    • 2.2 TreeSet 基本使用
    • 2.3 TreeSet 排序
  • 3 HashSet 类
    • 3.1 HashSet 类概述
    • 3.2 HashSet 基本使用
    • 3.3 哈希值
    • 3.4 HashSet 案例
  • 4 Map 集合
    • 4.1 Map 集合概述
    • 4.2 Map 常用方法
    • 4.3 Map 的遍历
  • 5 HashMap 类
    • 5.1 HashMap 类概述
    • 5.2 HashMap 案例
  • 6 TreeMap 类
    • 6.1 TreeMap 类概述
    • 6.2 TreeMap 案例
  • 7 可变参数与不可变集合
    • 7.1 可变参数
    • 7.2 不可变集合

1 Set 集合

1.1 Set 集合概述

Set 集合

  • 不可以存储重复元素(可以去除重复)
  • 存取顺序不一致
  • 没有索引,不能使用普通 for 循环遍历,也不能通过索引来获取、删除 Set 集合里面的元素

1.2 Set 集合的使用

存储字符串并遍历

public static void main(String[] args) {
    Set<String> set = new TreeSet<>();
    set.add("ccc");
    set.add("aaa");
    set.add("aaa");
    set.add("bbb");
    System.out.println(set); // [aaa, bbb, ccc]

    Iterator<String> it = set.iterator();
    while(it.hasNext()){
        System.out.print(it.next()+" "); // aaa bbb ccc
    }

    for (String s : set) {
        System.out.print(s+"*"); // aaa*bbb*ccc*
    }
}

2 TreeSet 类

2.1 TreeSet 类概述

TreeSet 类

  • 底层是红黑树,必须给定排序规则
  • 不可以存储重复元素
  • 没有索引
  • 可以将元素按照规则进行排序
    • TreeSet():根据其元素的自然排序进行排序
    • TreeSet(Comparator comparator):根据指定的比较器进行排序

2.2 TreeSet 基本使用

存储Integer类型的整数并遍历

public static void main(String[] args) {
    TreeSet<Integer> ts = new TreeSet<>();
    ts.add(5);
    ts.add(3);
    ts.add(4);
    ts.add(1);
    ts.add(2);

    System.out.println(ts); // [1, 2, 3, 4, 5]
}

存储学生对象并遍历

已存在学生类
测试类如下:

public static void main(String[] args) {
	TreeSet<Student> ts = new TreeSet<>();

	Student s1 = new Student("zhangsan",28);
	Student s2 = new Student("lisi",27);
	Student s3 = new Student("wangwu",29);
	Student s4 = new Student("zhaoliu",28);
	Student s5 = new Student("qianqi",30);

	ts.add(s1);
	ts.add(s2);
	ts.add(s3);
	ts.add(s4);
	ts.add(s5);

	System.out.println(ts);
}

运行测试类会报错,因为不知道按照什么规则(身高、年龄……)对学生对象排序。由此可得,想要使用TreeSet,需要指定排序规则。

2.3 TreeSet 排序

1. 自然排序Comparable的使用

案例需求:

  • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
  • 要求:按照年龄从小到大排序,如果年龄一样,则按照姓名首字母排序;如果姓名和年龄都一样,才认为是同一个学生对象,不存入。

实现步骤:

  • 使用空参构造创建TreeSet集合
    • 用TreeSet集合存储自定义对象,无参构造方法 使用的是自然排序对元素进行排序的
  • 自定义的Student类实现 Comparable接口
    • 自然排序,就是让元素所属的类实现Comparable接口,重写 compareTo(T o)方法
  • 重写接口中的compareTo方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

示例代码:

学生类

public class Student implements Comparable<Student>{ // Comparable接口有泛型且要跟集合的数据类型保持一致
    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.age - o.age; // this表示当前正在存的元素,o表示硬存的元素
        //次要判断条件(名字的字母序)
        result = result == 0 ? this.name.compareTo(o.getName()) : result;
        return result;
    }
}

测试类同上

在这里插入图片描述

注意:以下两个compareTo方法是不一样的

  • 第二个compareTo方法是字符串的方法
public static void main(String[] args) {
	String s1 = "aaa";
	String s2 = "ab";

	System.out.println(s1.compareTo(s2)); // -1
	//首先比较第一个字母,如果第一个字母是一样的,那么继续比较后面的字母
	//当不一样的时候,就拿着对应的码表值97,减去 b的码表值 98
	//认为a是比b要小的。
}

2. 比较器排序Comparator的使用

案例需求:

  • 存储老师对象并遍历,创建TreeSet集合使用带参构造方法
  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

实现步骤:

  • 用TreeSet集合存储自定义对象,带参构造方法 使用的是比较器排序对元素进行排序的
  • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

示例代码:

老师类

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

    public Teacher() {
    }

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

测试类

public static void main(String[] args) {
	TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
		@Override
		public int compare(Teacher o1, Teacher o2) {
			//o1表示现在要存入的那个元素
			//o2表示已经存入到集合中的元素

			//主要条件
			int result = o1.getAge() - o2.getAge();
			//次要条件
			result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
			return result;
		}
	});

	Teacher t1 = new Teacher("zhangsan",23);
	Teacher t2 = new Teacher("lisi",22);
	Teacher t3 = new Teacher("wangwu",24);
	Teacher t4 = new Teacher("zhaoliu",24);

	ts.add(t1);
	ts.add(t2);
	ts.add(t3);
	ts.add(t4);

	System.out.println(ts);
}

3. 两种比较方式

两种比较方式总结:

  • 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
  • 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
  • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序

两种方式中关于返回值的规则:

  • 如果返回值为负数,表示当前存入的元素是较小值,存左边
  • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
  • 如果返回值为正数,表示当前存入的元素是较大值,存右边

案例:按照字符串长短排序
要求:存入4个字符串“c”、“ab”、“df”、“qwer”,按照长度排序,如果一样长则按照首字母排序。请自行选择比较器排序和自然排序两种方式。

public static void main(String[] args) {
//        TreeSet<String> ts = new TreeSet<>();
//        ts.add("c");
//        ts.add("ab");
//        ts.add("df");
//        ts.add("qwer");
//        System.out.println(ts); // [ab, c, df, qwer]

    /*
     * 通过查看String源码可知,String类已经实现了Comparable接口,
     * 即String类的自然排序规则Java内部已经帮我们写好了,且默认规则为按照字母字典序排列
     * 所以我们应该选择比较器排序
     * */

    // 1. 匿名内部类方式
//        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                int result = o1.length() - o2.length();
//                result = result==0?o1.compareTo(o2):result;
//                return result;
//            }
//        });

    // 2. lambda函数方式
    TreeSet<String> ts = new TreeSet<>(
            (String o1, String o2)->{
                int result = o1.length() - o2.length();
                result = result == 0 ? o1.compareTo(o2) : result;
                return result;
            }
    );


    ts.add("c");
    ts.add("ab");
    ts.add("df");
    ts.add("qwer");
    System.out.println(ts); // [ab, c, df, qwer]
}

3 HashSet 类

3.1 HashSet 类概述

HashSet类

  • 底层数据结构是哈希表
  • 不能保证存储和取出的顺序完全一致
  • 是Set集合,元素唯一,不可以存储重复元素
  • 没有索引,不能使用普通 for 循环遍历

3.2 HashSet 基本使用

存储字符串并遍历

public static void main(String[] args) {
	HashSet<String> hs = new HashSet<>();

	hs.add("hello");
	hs.add("world");
	hs.add("java");
	hs.add("java");
	hs.add("java");
	hs.add("java");
	hs.add("java");
	hs.add("java");

	Iterator<String> it = hs.iterator();
	while(it.hasNext()){
		String s = it.next();
		System.out.println(s);
	}
	System.out.println("=============================");

	for (String s : hs) {
		System.out.println(s);
	}
}

3.3 哈希值

哈希值(哈希码值):

  • 是JDK根据对象的 地址 或者 属性值,算出来的 int 类型的整数

哈希值的特点:

  • 如果没有重写hashCode() 方法,那么是根据对象的地址值计算出的哈希值。同一个对象多次调用 hashCode() 方法返回的哈希值是相同的,不同对象的哈希值是不同的
  • 而重写 hashCode() 方法,一般都是通过对象的属性值计算出哈希值。如果不同的对象属性值是一样的,那么计算出的哈希值也是一样的
    • Alt+Insert选择equals() and hashCode(),默认选项直接next,自动生成重写方法

获取哈希值:

  • Object类中的 public int hashCode():返回对象的哈希码值

示例代码:

学生类

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


    //我们可以对Object类中的hashCode方法进行重写
    //在重写之后,就一般是根据对象的属性值来计算哈希值的。
    //此时跟对象的地址值就没有任何关系了。
    @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 +
                '}';
    }
}

测试类

public static void main(String[] args) {
	Student s1 = new Student("xiaozhi",23);
	Student s2 = new Student("xiaomei",22);

	// 1. 同一个对象多次调用hashCode()时其返回值一样
	// 因为在Object类中,是根据对象的地址值计算出来的哈希值。
	System.out.println(s1.hashCode());//1060830840
	System.out.println(s1.hashCode());//1060830840
	 
	// 2. 不同对象的哈希值是不一样的
	System.out.println(s2.hashCode());//2137211482
}

3.4 HashSet 案例

案例需求:

  • 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
  • 学生对象的成员变量值相同,我们就认为是同一个对象

代码实现:
学生类

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

测试类

public static void main(String[] args) {
	HashSet<Student> hs = new HashSet<>();

	Student s1 = new Student("xiaohei",23);
	Student s2 = new Student("xiaohei",23);
	Student s3 = new Student("xiaomei",22);

	hs.add(s1);
	hs.add(s2);
	hs.add(s3);

	for (Student student : hs) {
		System.out.println(student); // 打印结果去除重复对象
	}
}

如果HashSet集合要存储自定义对象,那么必须重写hashCode和equals方法。

4 Map 集合

4.1 Map 集合概述

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

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

4.2 Map 常用方法

在这里插入图片描述

示例代码:

public static void main(String[] args) {
	Map<String,String> map = new HashMap<>();
	map.put("itheima001","小智");
	map.put("itheima002","小美");
	map.put("itheima003","大胖");
	map.put("itheima004","小黑");
	map.put("itheima005","大师");

	//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("itheima001");
	boolean result2 = map.containsKey("itheima006");
	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("itheima001", "aaa");
	System.out.println(s);
	System.out.println(map);
}

4.3 Map 的遍历

在这里插入图片描述

  1. 第一种遍历方式
  • 遍历思路
    • 我们刚才存储的元素都是成对出现的,所以我们把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();
	//遍历Set集合得到每一个键
	for (String key : keys) {
		//通过每一个键key,来获取到对应的值
		String value = map.get(key);
		System.out.println(key + "---" + value);
	}
}
  1. 第2种遍历方式
  • 遍历思路

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

    • 获取所有键值对对象的集合
      • 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对象)
	//而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);
	}
}

5 HashMap 类

5.1 HashMap 类概述

  • HashMap底层是哈希表结构的
  • 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
  • 依赖hashCode方法和equals方法保证 的唯一
  • 如果 要存储的是自定义对象,需要重写hashCode和equals方法(hashCode不同时,则必为不同对象。hashCode相同时,根据equlas()方法判断是否为同一对象。)

5.2 HashMap 案例

  • 案例需求
    • 创建一个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 +
                '}';
    }
}

测试类

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,"天津");

	//第一种:先获取到所有的键,再通过每一个键来找对应的值
	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);
			}
	);
}

6 TreeMap 类

6.1 TreeMap 类概述

  • TreeMap底层是红黑树结构
  • 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
  • 依赖自然排序或者比较器排序,对 进行排序
  • 如果 存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

6.2 TreeMap 案例

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

(1)自然排序方式

学生类

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) 比较器排序

学生类

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

7 可变参数与不可变集合

7.1 可变参数

  • 可变参数介绍

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

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

示例代码

// 需求:定义一个方法求N个数的和
public static void main(String[] args) {
	int sum1 = getSum(1, 2, 3, 4, 5);
	System.out.println(sum1);
}

public static int getSum(int number,int... arr) {
	int sum = 0;
	for (int i = 0; i < arr.length; i++) {
		sum = sum + arr[i];
	}
	return sum;
}

注意:

  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

7.2 不可变集合

  • 在List、Set、Map接口中,都存在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);
}

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161716.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql:存储过程的创建与使用

一、创建存储过程 使用MySql Workbench创建存储过程&#xff0c;一定要记得使用delimiter指明结束符&#xff0c;否则会报错&#xff1a;Statement is incomplete, expecting: ;’ 错误示例&#xff1a; create procedure area_pro1(in mylevel tinyint) beginselect * from…

回看2022,展望2023

目录一、回看2022求职心路身份过度二、展望20232023年&#xff0c;祝大家天天开心&#xff0c;身体健康&#xff0c;万事如意&#xff0c;一起加油&#xff01;一、回看2022 求职心路 2022年过去了&#xff0c;2023年到来了。在2022年我印象比较深刻的是8-11月份的日子&#…

【正点原子FPGA连载】第十六章Petalinux设计流程实战摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十六章Petalin…

大数据必学Java基础(一百二十一):Maven项目结构介绍

文章目录 Maven项目结构介绍 一、标准目录结构 二、结构图 Maven项目结构介绍 一、标准目录结构

商场导视图用什么软件做,专业、便捷的室内电子地图绘制平台

在一些大型商场&#xff0c;顾客很多时候找不到店铺和需要的商品、不了解商家的优惠促销信息、大型活动日排队和消费等等。在这个全民习惯于手机导航的时代&#xff0c;假如商场的活动信息也能够全部显示在手机上&#xff0c;并且能实时的进行导航&#xff0c;那该有多方便&…

剑指offer----C语言版----第十八天----面试题24:反转链表

目录 1. 反转链表 1.1 题目描述 1.2 思路一&#xff1a;反转指针 1.3 思路二&#xff1a;头插到新链表 1.4 往期回顾 1. 反转链表 原题链接&#xff1a; 剑指 Offer 24. 反转链表 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/fan-zhuan-lian-biao-…

4700. 何以包邮?(简单的dp 01背包思想)

题目如下&#xff1a; 输入样例1&#xff1a; 4 100 20 90 60 60输出样例1&#xff1a; 110样例1解释 购买前两本书 (2090) 即可包邮且花费最小。 输入样例2&#xff1a; 3 30 15 40 30输出样例2&#xff1a; 30样例2解释 仅购买第三本书恰好可以满足包邮条件。 输入样例…

分享128个ASP源码,总有一款适合您

分享128个ASP源码&#xff0c;总有一款适合您 ASP源码 分享128个ASP源码&#xff0c;总有一款适合您 链接&#xff1a;https://pan.baidu.com/s/1FXTm501s200ASY8XYTIk7w?pwd474b 提取码&#xff1a;474b 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不…

安凯微在科创板IPO过会:计划募资10亿元,小米等为其股东

1月13日&#xff0c;上海证券交易所披露的信息显示&#xff0c;广州安凯微电子股份有限公司&#xff08;下称“安凯微”&#xff09;首发符合发行条件、上市条件和信息披露要求&#xff0c;即IPO过会。目前&#xff0c;安凯微的上市申请状态已经变更为“上市委会议通过”。 本次…

线程学习基础(1):单线程爬虫和多线程爬虫的效率比照

线程学习基础&#xff1a;单线程爬虫和多线程爬虫的效率比照1. 并发线程的需求2. 线程提速方法3. 如何选择并发编程的三种方式3.1 什么是CPU密集型计算、IO密集型计算&#xff1f;3.1.1 CPU密集型&#xff08;CPU-bound)3.1.2 IO密集型&#xff08;IO-bound)3.2 多线程Thread、…

三维空间中散点平面拟合方法

1、三点求平面方程、平面法向量和点到平面的距离 已知三点p1&#xff08;x1,y1,z1&#xff09;&#xff0c;p2(x2,y2,z2)&#xff0c;p3(x3,y3,z3)&#xff0c; 要求确定的平面方程,关键在于求出平面的一个法向量 为此做向量p1p2&#xff08;x2-x1,y2-y1,z2-z1), p1p3(x3-x1,…

Linux-8 用户管理

Linux-8 用户管理 什么是用户&#xff1f; Linux/Windows通过用户来管理和维护系统&#xff1b; Windows下的管理员用户&#xff1a;AdministratorLinux下的管理员用户&#xff1a;root Windows/Linux都是多用户系统 Windows同一时间只能使用1个用户Linux可以多用户同时登陆&…

STL - Vector容器

基本概念 功能&#xff1a; vector数据结构和数组十分类似&#xff0c;也成为单端数组 vector和普通数组的区别&#xff1a; 不同之处在于数组是静态空间&#xff0c;而vector可以动态扩展 动态扩展&#xff1a; 并不是在原空间后续再接空间&#x…

【pandas】用户手册:10分钟熟悉pandas(下)

数据分组 Splitting : 利用某些条件将数据进行分组Applying : 函数应用于每个单独的分组Combining : 合并最终的结果 df pd.DataFrame({"A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo&q…

【正点原子FPGA连载】第十四章Linux基础外设的使用 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十四章Linux基…

百趣代谢组学文献分享:间歇性禁食调节糖尿病脑损伤多组学研究

百趣代谢组学文献分享&#xff0c;糖尿病已经成为一个全球问题&#xff0c;国际糖尿病联盟&#xff08;IDF&#xff09;发布的全球糖尿病地图&#xff08;第9版&#xff09;[1]显示&#xff0c;全球糖尿病患者人数不断上升&#xff0c;全球平均增长率为51%&#xff0c;目前有4.…

C#,图像二值化(23)——局部阈值的绍沃拉算法(Sauvola Thresholding)及源程序

1、局部阈值的绍沃拉算法&#xff08;Sauvola Thresholding&#xff09;Niblack和Sauvola阈值算法Niblack和Sauvola阈值是局部阈值技术&#xff0c;对于背景不均匀的图像非常有用&#xff0c;尤其是对于文本识别1、2。代替为整个图像计算单个全局阈值&#xff0c;通过使用考虑到…

【5】K8S_Deployment

目录 1、Deployment作用 2、deployment的冗余能力 3、deployment的多副本部署 4、deployment的扩缩容 5、deployment的自愈能力 6、滚动更新 7、版本回退 1、Deployment作用 控制Pod&#xff0c;使Pod拥有多副本&#xff0c;自愈&#xff0c;扩缩容等能力 2、deployme…

【正点原子FPGA连载】第十五章开发环境搭建 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十五章开发环境…

uniapp 窗口小工具、桌面小部件、微件(日历、时间) Ba-AwCalendarS

简介&#xff08;下载地址&#xff09; Ba-AwCalendarS 是一款窗口小工具&#xff08;桌面小部件、微件&#xff09;插件&#xff0c;默认为简单的时间样式&#xff0c;有其他界面需要&#xff0c;可联系作者定制。 支持定时更新&#xff08;本插件为每分钟&#xff09;支持点…