Java集合(进阶)

news2024/12/25 13:01:36

Java集合

  • Collection集合体系结构
    • Collection
      • Collection系列集合三种遍历方式
    • List
    • 泛型
      • 泛型类
      • 泛型方法
      • 泛型接口
      • 泛型的继承和通配符
    • Set
      • HashSet
      • TreeSet
    • 总结:
  • Map(双列集合)
    • HashMap
      • LinkedHashMap
    • TreeMap
  • 可变参数
  • 集合工具类Collections
  • 集合嵌套案例
  • 不可变集合
  • 集合练习1:随机点名(1)
  • 集合练习2:随机点名(2)
  • 集合练习3:斗地主(准备牌、洗牌、发牌、看牌)

Collection集合体系结构

在这里插入图片描述

  • List系列集合:添加的元素是有序、可重复、有索引
  • Set系列集合:添加的元素是无序、不重复、无索引

Collection

  • Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
    在这里插入图片描述
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo1 {
    public static void main(String[] args) {
       //注意:Collection是一个接口,我们不能直接创建它的对象。所以,
        // 我们只能创建它实现类的对象。实现类:ArrayList
        Collection<String> coll = new ArrayList<>();
        //1、添加元素
        /*
        如果我们要往List系列集合中添加元素,那么方法永远是true,因为List系列
        允许重复。往Set系列集合中添加元素,在有重复元素的情况下会添加失败,返回false
         */
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        System.out.println(coll);
        //2、清空元素
        //coll.clear();
        //3、删除
        //因为Collection里面定义的是共性方法,所以此时不能通过索引进行删除
        //只能通过元素对象进行删除
        coll.remove("aaa");
        System.out.println(coll);
        //4、判断元素是否包含
        //底层是依赖equals方法进行判断是否存在。所以,如果集合中存储的是自定义对象,
        //也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法
        boolean result = coll.contains("bbb");
        System.out.println(result);//true
        //5、判断集合是否为空
        boolean result2 = coll.isEmpty();
        System.out.println(result2);//false
        //6、获取集合的长度
        int size = coll.size();
        System.out.println(size);//2
    }
}

Collection系列集合三种遍历方式

1、迭代器遍历

  • 迭代器在Java中的类是iterator,迭代器是集合专用的遍历方式。
    Collection系列集合三种通用的遍历方式
    1、迭代器遍历
    2、增强for遍历
    3、lambda表达式遍历

  • Collection集合获取迭代器:在这里插入图片描述

  • iterator中的常用方法
    在这里插入图片描述

  • 迭代器遍历相关的三个方法:
    Iterator< E> iterator() : 获取一个迭代器对象
    boolean hasNext() : 判断当前指向的位置是否有元素
    E next() : 获取当前指向的的元素并移动指针

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo2 {
    public static void main(String[] args) {
        //1、创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        //2、获取迭代器对象
        //迭代器就好比是一个箭头,默认指向集合的0索引处
        Iterator<String> it = coll.iterator();
        //3、利用循环不断的去获取集合中的每一个元素
        while(it.hasNext()){
            String str = it.next();//4、next方法的两件事情:获取元素并移动指针
            System.out.println(str);
        }
        //当上面循环结束之后,迭代器的指针已经指向了最后没有元素的位置
        //System.out.println(it.next());NoSuchElementException
        //迭代器遍历完毕,指针不会复位,如果要继续第二次遍历集合,只能再次获取一个新的迭代器对象
        System.out.println(it.hasNext());//false
        //循环中只能用一次next方法
        //在用迭代器遍历的时候,不能用集合的方法进行增加或者删除
        //删除可以使用迭代器提供的remove方法进行删除,添加暂时没有办法
        Iterator<String> it2 = coll.iterator();
        while (it2.hasNext()){
            String str2 = it2.next();
            if("bbb".equals(str2)){
                //coll.remove("bbb");
                it2.remove();
            }
        }
        System.out.println(coll);
    }
}

2、增强for遍历

  • 增强for的底层就是迭代器,为了简化迭代器的代码书写的。
  • 它是JDK5之后出现的,其内部原理就是一个iterator迭代器。
  • 所有的单列集合数组才能用增强for进行遍历。

格式:
for(元素的数据类型 变量名 : 数组或者集合){
}
例如:
for(String s : list){
System.out.println(s);
}

import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo3 {
    public static void main(String[] args) {
        //1、创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("zhangsan");
        coll.add("lisi");
        coll.add("wangwu");
        //2、利用增强for进行遍历
        //快速生成方式:集合的名字 + for 回车
        //注意:s其实就是一个第三方变量,在循环的过程中依次表示集合中的每一个数据
        //修改增强for中的变量,不会改变集合中原本的数据
        for (String s : coll) {
            System.out.println(s);
        }
    }
}

3、Lambda表达式遍历
在这里插入图片描述

import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo3 {
    public static void main(String[] args) {
        //1、创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("zhangsan");
        coll.add("lisi");
        coll.add("wangwu");
        //2、利用lambda表达式
        coll.forEach(s-> System.out.println(s));
        }
  }

List

List集合的特有方法:

  • Collection的方法List都继承了
  • List集合因为有索引,所以多了很多索引操作的方法。
    在这里插入图片描述
import java.util.ArrayList;
import java.util.List;
public class ListDemo1 {
    public static void main(String[] args) {
        //1、创建一个集合
        List<String> list = new ArrayList<>();

        //2、添加元素
        list.add("aaa");
        list.add("bbb");//索引为1
        list.add("ccc");
        //原来索引上的元素会往后移
        list.add(1,"QQQ");
        //3、删除元素
        //在调用方法时,如果方法出现了重载现象,优先调用
        //实参和形参类型一致的那个方法。
        String remove = list.remove(0);
        System.out.println(remove);//aaa
        //4、修改元素
        String result = list.set(2, "QQQ");
        System.out.println(result);//ccc
        //5、返回指定索引处的元素
        String s = list.get(0);
        System.out.println(s);//QQQ
        //3、打印集合
        System.out.println(list);
    }
}

List集合的5种遍历方式
1、迭代器
2、增强for
3、Lambda表达式

4、普通for循环

 for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }

5、列表迭代器

//列表迭代器
        //获取一个列表迭代器对象,里面的指针默认也是0索引的
        //额外添加了一个方法:在遍历过程中,可以添加元素
        ListIterator<String> it = list.listIterator();
        while (it.hasNext()){
            String str = it.next();
            if("bbb".equals(str)){
                it.add("qqq");
            }
        }
        System.out.println(list);

泛型

  • 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
  • 泛型的格式:<数据类型>
  • 注意:泛型只能支持引用数据类型。
  • 泛型的好处:
    1、统一数据类型。
    2、把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
  • 泛型的细节:
    1、泛型中不能写基本数据类型
    2、指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
    3、如果不写泛型,类型默认是Object

泛型类

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类。
格式:修饰符 class 类名 <类型>{
}
泛型类:

import java.util.Arrays;
public class MyArrayList<E> {
    Object[] obj = new Object[10];
    int size;
    /*
    E:表示不确定的类型,该类型在类名后面已经定义过了。
    e:形参的名字,变量名
     */
    public boolean add(E e){
        obj[size] = e;
        size++;
        return true;
    }

    public E get(int index){
        return (E)obj[index];
    }

    @Override
    public String toString() {
        return Arrays.toString(obj);
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        System.out.println(list);

        MyArrayList<Integer> list2 = new MyArrayList<>();
        list2.add(123);
        list2.add(456);
        list2.add(789);
        int i = list2.get(0);
        System.out.println(i);
        System.out.println(list2);
    }
}

泛型方法

适用场景:方法中形参类型不确定时
方案1:使用类名后面定义的泛型。(所有方法都能用)
方案2:在方法申明上定义自己的泛型。(只有本方法能用)
格式:
修饰符 <类型> 返回值类型 方法名(类型 变量名){
}
泛型方法:

import java.util.ArrayList;
public class ListUtil {
    private ListUtil(){}
    //类中定义一个静态方法addAll,用来添加多个集合的元素。
    /*
    参数1:集合
    参数2:要添加的元素
     */
    public static<E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4){
        list.add(e1);
        list.add(e2);
        list.add(e3);
        list.add(e4);
    }
    public void show(){
        System.out.println("-------");
    }
}

测试:

import java.util.ArrayList;
public class Test {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        ListUtil.addAll(list1,"aaa","bbb","ccc","ddd");
        System.out.println(list1);

        ArrayList<Integer> list2 = new ArrayList<>();
        ListUtil.addAll(list2,1,2,3,4);
        System.out.println(list2);
    }
}

泛型接口

格式:
修饰符 interface 接口名<类型>{
}
使用方式:
方式1:实现类给出具体类型。
方式2:实现类延续泛型,创建对象时再确定。

public class MyArrayList3<E> implements List<E>{
}

泛型的继承和通配符

  • 泛型不具备继承性,但是数据具备继承性
import java.util.ArrayList;
public class GenericsDemo {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();

        ArrayList<Student> list4 = new ArrayList<>();

        method(list1);
        method(list2);
        method(list3);
        //method(list4);不可以使用method方法
    }
    /*
    ? 表示不确定的类型,可以进行类型的限定
    ? extends E: 表示可以传递E或者E所有的子类类型
    ? super E: 表示可以传递E或者E所有的父类类型
         */
    /*
    应用场景:
    1、如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类,泛型方法、泛型接口。
    2、如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以用泛型的通配符。
    泛型的通配符:
    关键点:可以限定类型的范围。
     */
    public static void method(ArrayList<? extends Ye> list) {

    }

}
    class Ye{

    }
    class Fu extends Ye{

    }
    class Zi extends Fu{

    }
    class Student{

    }

Set

Set系列集合

  • 无序:存取顺序不一致
  • 不重复:可以去除重复
  • 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素

Set集合的实现类

  • HashSet:无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:可排序、不重复、无索引

Set接口中的方法上基本上与Collection的API一致。

例如:使用Set系列集合,添加字符串,并使用多种方式遍历

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetDemo1 {
    public static void main(String[] args) {
        //1、创建一个Set集合的对象
        Set<String> s = new HashSet<>();
        //2、添加元素
        //如果当前元素是第一次添加,那么可以添加成功,返回true
        //如果当前元素是第二次添加,那么添加失败,返回false
        s.add("张三");
        s.add("张三");
        s.add("李四");
        s.add("王五");
        //3、打印集合
        //无序
        //System.out.println(s);//[李四, 张三, 王五]

        //迭代器遍历
        Iterator<String> it = s.iterator();
        while (it.hasNext()){
            String str = it.next();
            System.out.println(str);
        }
        //增强for
        for (String str : s) {
            System.out.println(str);
        }
        //Lambda表达式
        s.forEach(str-> System.out.println(str));
    }
}

HashSet

HashSet底层原理

  • HashSet集合底层采取哈希表存储数据
  • 哈希表是一种对于增删改查数据性能都较好的结构

哈希表组成

  • JDK8之前:数组+链表
  • JDK8之后:数组+链表+红黑树

哈希值

  • 根据hashCode方法算出来的int类型的整数
  • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
  • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

对象的哈希值特点

  • 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
  • 如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
  • 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
import java.util.Objects;
public class HashSetDemo1 {
    public static void main(String[] args) {
        Student1 s1 = new Student1("zhangsan",23);
        Student1 s2 = new Student1("lisi",23);

        System.out.println(s1.hashCode());//-1461067292
        System.out.println(s2.hashCode());//102983077
        //哈希碰撞
        System.out.println("abc".hashCode());//96354
        System.out.println("acD".hashCode());//96354
    }
}

LinkedHashSet底层原理

  • 有序、不重复、无索引。
  • 这里的有序指的是保证存储和取出的元素顺序一致
  • 原理:底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        //创建四个学生对象
        //要重写hashCode方法和equals方法
        Student1 s1 = new Student1("zhangsan",23);
        Student1 s2 = new Student1("lisi",24);
        Student1 s3 = new Student1("wangwu",25);
        Student1 s4 = new Student1("zhangsan",23);
        //创建集合对象
        LinkedHashSet<Student1> lhs = new LinkedHashSet<>();
        //添加元素
        System.out.println(lhs.add(s1));//true
        System.out.println(lhs.add(s2));//true
        System.out.println(lhs.add(s3));//true
        System.out.println(lhs.add(s4));//false
        //打印集合
        System.out.println(lhs);
        //[Student1{name = zhangsan, age = 23}, 
        // Student1{name = lisi, age = 24}, Student1{name = wangwu, age = 25}]
    }
}

TreeSet

TreeSet的特点

  • 不重复、无索引、可排序
  • 可排序:按照元素的默认规则(由小到大)排序。
  • TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。

例如:利用TreeSet存储整数并进行排序

import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo1 {
    public static void main(String[] args) {
        //1、创建TreeSet集合对象
        TreeSet<Integer> ts = new TreeSet<>();
        //2、添加元素
        ts.add(4);
        ts.add(5);
        ts.add(1);
        ts.add(3);
        ts.add(2);
        //3、打印集合
        System.out.println(ts);//[1, 2, 3, 4, 5]
        //遍历集合
        Iterator<Integer> it = ts.iterator();
        while (it.hasNext()){
            Integer i = it.next();
            System.out.println(i);
        }
        System.out.println("------------------");
        //增强for
        for (Integer t : ts) {
            System.out.println(t);
        }
        System.out.println("------------------");
        //Lambda表达式
        ts.forEach(i-> System.out.println(i));
    }
}

TreeSet集合默认的规则

  • 对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序。
  • 对于字符、字符串类型:按照ASCII码表中的数字升序进行排序。

排序规则:

  • 方式1:
    默认的排序规则/自然排序:
    Student1实现Comparable接口,重写里面的抽象方法,再指定比较规则
  • 方式2:
    比较器排序:
    创建TreeSet对象的时候,传递比较器Comparator指定规则

使用规则:默认使用第一种,如果第一种不能满足当前需求,就使用第二种。

import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo3 {
    public static void main(String[] args) {
        //采取第二种排序方式:比较器排序
        //1、创建集合
        //o1:表示当前要添加的元素
        //o2:表示已经在红黑树存在的元素
        //方法返回值特点:
        //负数:表示当前要添加的元素是小的,存左边
        //正数:表示当前要添加的元素是大的,存右边
        //0:表示当前要添加的元素已经存在,舍弃
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //按照长度排序
                int i = o1.length() - o2.length();
                //如果一样长则按照首字母排序
                i = i == 0 ? o1.compareTo(o2) : i;
                return i;
            }
        });
        //2、添加元素
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");
        //3、打印集合
        System.out.println(ts);//[c, ab, df, qwer]
    }
}

总结:

1、如果想要集合中的元素可重复

  • 用ArrayList集合,基于数组的。(用的最多)

2、如果想要集合中的元素可重复,而且当前的增删操作明显多于查询

  • 用LinkedList集合,基于链表的。

3、如果想要对集合中的元素去重

  • 用HashSet集合,基于哈希表的。(用的最多)

4、如果想要对集合中的元素去重,而且保证存取顺序

  • 用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet。

5、如果想要对集合中的元素进行排序

  • 用TreeSet集合,基于红黑树。后续也可以用List集合实现排序

Map(双列集合)

双列集合的特点:

  1. 双列集合一次需要存一对数据,分别为键和值
  2. 键不能重复,值可以重复
  3. 键和值是一一对应的,每一个键只能找到自己对应的值
  4. 键+值这个整体我们称之为“键值对”或者“键值对对象”,在java中叫做“Entry对象”

Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
在这里插入图片描述

import java.util.HashMap;
import java.util.Map;
public class MapDemo1 {
    public static void main(String[] args) {
        //1、创建Map集合的对象
        Map<String,String> m = new HashMap<>();
        //2、添加元素
        //put方法细节:添加/覆盖
        //在添加数据的时候,如果键不存在,那么直接把键值对对象添加到Map集合当中,方法返回null
        //在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回
        String value1 = m.put("0", "000");
//        System.out.println(value1);//null
        m.put("1","100");
        m.put("2","200");
//        String value2 = m.put("1", "300");
//        System.out.println(value2);//100
        //删除
//        String result = m.remove("1");
//        System.out.println(result);//100
        //清空
//        m.clear();
        //判断是否包含
        boolean KeyResult = m.containsKey("0");
        System.out.println(KeyResult);//true

        boolean valueResult = m.containsValue("100");
        System.out.println(valueResult);//true

        boolean result = m.isEmpty();
        System.out.println(result);//false

        int size = m.size();
        System.out.println(size);//3
        //3、打印集合
        System.out.println(m);//{0=000, 1=300, 2=200}
    }
}

Map集合的遍历方式:
1、通过键找值:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo2 {
    public static void main(String[] args) {
        //Map集合的第一种遍历方式
        //1、创建Map集合对象
        Map<String,String> map = new HashMap<>();
        //2、添加元素
        map.put("0","000");
        map.put("1","100");
        map.put("2","200");
        //3、通过键找值
        //3.1获取所有的键,把这些键放到一个单列集合当中
        Set<String> keys = map.keySet();
        //3.2遍历单列集合,得到每一个键
        for (String key : keys) {
            //System.out.println(key);
            //3.3利用Map集合中的键获取对应的值 get
            String value = map.get(key);
            System.out.println(key + " = " + value);
        }
    }
}

2、通过键值对对象进行遍历:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo3 {
    public static void main(String[] args) {
        //Map集合的第二种遍历方式
        //1、创建Map集合的对象
        Map<String,String> map = new HashMap<>();
        //2、添加元素
        map.put("0","000");
        map.put("1","100");
        map.put("2","200");
        //3.Map集合的第二种遍历方式
        //通过键值对对象进行遍历
        //3.1通过一个方法获取所有的键值对对象,返回一个Set集合
        Set<Map.Entry<String,String>> entries = map.entrySet();
        //3.2遍历entries这个集合,去得到里面的每一个键值对对象
        for (Map.Entry<String, String> entry : entries) {
            //3.3利用entry调用get方法获取键和值
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
    }
}

3、通过Lambda表达式遍历
在这里插入图片描述

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class MapDemo4 {
    public static void main(String[] args) {
        //Map集合的第三种遍历方式
        //1、创建Map集合
        Map<String,String> map = new HashMap<>();
        //2、添加元素
        map.put("0","000");
        map.put("1","100");
        map.put("2","200");
        //3、利用Lambda表达式
        //底层:
        //forEach其实就是利用第二种遍历方式进行遍历,依次得到每一个键和值
        //再调用accept方法
        map.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.println(key + "=" + value);
            }
        });
        System.out.println("---------------------");
        map.forEach((key,value) ->System.out.println(key + "=" + value));
    }
}

HashMap

HashMap的特点

  1. HashMap是Map里面的一个实现类。
  2. 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了。
  3. 特点都是由键决定的:无序、不重复、无索引
  4. HashMap跟HashSet底层原理是一模一样的,都是哈希表结构

HashMap总结

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

需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。存储三个键值对元素,并遍历。
要求:同姓名,同年龄认为是同一个学生
核心点:HashMap的键位置如果存储的是自定义对象,需要重写hashCode和equals方法

import java.util.HashMap;
import java.util.Set;
public class HashMapDemo1 {
    public static void main(String[] args) {
        //1、创建HashMap的对象
        HashMap<Student,String> hm = new HashMap<>();
        //2、创建三个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("wangwu",25);
        //3、添加元素
        hm.put(s1,"江苏");
        hm.put(s2,"浙江");
        hm.put(s3,"福建");
        hm.put(s4,"山东");
        //4、遍历集合
        Set<Student> keys = hm.keySet();
        for (Student key : keys) {
            String value = hm.get(key);
            System.out.println(key + "=" + value);
        }
    }
}

LinkedHashMap

  • 由键决定:有序,不重复、无索引
  • 这里的有序指的是保证存储和取出的元素顺序一致
  • 原理:底层数据结构是哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
import java.util.LinkedHashMap;
public class LinkedHashMapDemo1 {
    public static void main(String[] args) {
        //1、创建集合
        LinkedHashMap<Integer, String> lhm = new LinkedHashMap<Integer, String>();
        //2、添加元素
        lhm.put(3,"c");
        lhm.put(1,"a");
        lhm.put(1,"b");
        lhm.put(4,"d");
        //3、打印集合
        System.out.println(lhm);//{3=c, 1=b, 4=d}
    }
}

TreeMap

  • TreeMap跟TreeSet底层原理一样,都是红黑树结构
  • 由键决定特性:不重复、无索引、可排序
  • 可排序:对键进行排序
  • 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则

代码书写两种排序规则

  • 实现Comparable接口,指定比较规则。
  • 创建集合时传递Comparable比较器对象,指定比较规则。
import java.util.Comparator;
import java.util.TreeMap;
//需求:
//1、按键值升序输出(默认升序)
//2、按键值降序输出(重写compare方法)
public class TreeMapDemo1 {
    public static void main(String[] args) {
        //1、创建集合
        TreeMap<Integer, String> tm = new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //o1:当前要添加的元素
                //o2:表示已经在红黑树中存在的元素
                return o2 - o1;
            }
        });
        //2、添加元素
        tm.put(5,"e");
        tm.put(4,"d");
        tm.put(3,"c");
        tm.put(2,"b");
        tm.put(1,"a");
        //3、打印集合
        System.out.println(tm);
    }
}

可变参数

  • 格式:属性类型…名字
  • 作用:在形参中接收多个数据
  • int…args
  • 底层:可变参数底层就是一个数组
  • 细节:1、在方法的形参中最多只能写一个可变参数
    2、在方法当中,如果除了可变参数以外,还有其它的形参,那么可变参数要写在最后
public class ArgsDemo1 {
    public static void main(String[] args) {
        int sum = getsum(1, 2, 3,4,5,6);
        System.out.println(sum);//21
    }
    public static int getsum(int...args){
        int sum = 0;
        for (int i : args) {
            sum += i;
        }
        return sum;
    }
}

集合工具类Collections

  • 作用:Collections不是集合,而是集合的工具类。
  • Collections常用的API
    在这里插入图片描述
    在这里插入图片描述
import java.util.ArrayList;
import java.util.Collections;
public class CollectionsDemo1 {
    public static void main(String[] args) {
        //addAll批量添加元素
        //1、创建集合对象
        ArrayList<String> list = new ArrayList<>();
        //2、批量添加元素
        Collections.addAll(list,"abc","bcd","qwer","df");
        //3、打印集合
        System.out.println(list);//[abc, bcd, qwer, df]
        //shuffle打乱
        Collections.shuffle(list);
        System.out.println(list);//[df, qwer, bcd, abc]
    }
}

集合嵌套案例

import java.util.*;
public class Test4 {
    public static void main(String[] args) {
        //1、创建集合
        HashMap<String, ArrayList<String>> hm = new HashMap<>();
        //2、创建单列集合
        ArrayList<String> list1 = new ArrayList<String>();
        ArrayList<String> list2 = new ArrayList<String>();
        ArrayList<String> list3 = new ArrayList<String>();
        Collections.addAll(list1, "1","2","3","4","5");
        Collections.addAll(list2, "10","20","30","40","50");
        Collections.addAll(list3, "100","200","300","400","500");
        //3、添加集合
        hm.put("一位数",list1);
        hm.put("两位数",list2);
        hm.put("三位数",list3);
        //4、遍历集合
        Set<Map.Entry<String, ArrayList<String>>> entries = hm.entrySet();
        for (Map.Entry<String, ArrayList<String>> entry : entries) {
            String key = entry.getKey();
            ArrayList<String> value = entry.getValue();
            StringJoiner sj = new StringJoiner(", ","","");
            for (String list : value) {
                    sj.add(list);
            }
            System.out.println(key + " = " + sj);
        }
    }
}

输出结果:

三位数 = 100, 200, 300, 400, 500 
两位数 = 10, 20, 30, 40, 50 
一位数 = 1, 2, 3, 4, 5

不可变集合

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

  • 创建不可变集合的书写格式
    在List、Set、Map接口中,都存在静态的of方法,可以获取一个不可变的集合。
    在这里插入图片描述
    注意:这个集合不能添加,不能修改,不能删除。

import java.util.Iterator;
import java.util.List;
public class ImmutableDemo1 {
    public static void main(String[] args) {
        //1、创建集合并添加元素
        List<String> list = List.of("p1","p2","p3");
        //2、遍历集合
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
    }
}

细节:
1、当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性。
2、对于Map集合来说,键是不能重复的。
3、Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对,超过10个同ofEntries方法。

创建Map的不可变集合,键值对的数量超过10个:

import java.util.*;
public class ImmutableDemo2 {
    public static void main(String[] args) {
       //1、创建一个普通的Map集合
        HashMap<String,String> hm =new HashMap<>();
        //2、添加元素
        hm.put("1","100");
        hm.put("2","200");
        hm.put("3","300");
        //简化1:
        Map<String, String> map = Map.copyOf(hm);//(JDK10以上)
        //简化2:
        //Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
//        //3、利用上面的数据来获取一个集合
//        //获取到所有的键值对对象(Entry对象)
//        Set<Map.Entry<String, String>> entries = hm.entrySet();
//        //把entries变成一个数组
//        Map.Entry[] arr1 = entries.toArray(new Map.Entry[0]);
//       //toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//        //如果集合长度 > 数组的长度:数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//        //如果集合长度 <= 数组的长度:数据在数组中放得下,此时不会创建新数组,而是直接使用
//        Map.Entry[] arr2 = entries.toArray(arr1);
//        不可变的Map集合
//        Map map = Map.ofEntries(arr2);
        map.put("bbb",222);不可添加数据
    }
}

集合练习1:随机点名(1)

需求:随机点名,其中男生的概率70%,女生30%

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Test2 {
    public static void main(String[] args) {
        //1、创建集合
        ArrayList<Integer> list = new ArrayList<>();
        //2、向集合中添加数据
        Collections.addAll(list,1,1,1,1,1,1,1,0,0,0);
        //3、打乱集合
        Collections.shuffle(list);
        System.out.println(list);
        //4、从list集合中随机抽取0或1
        Random r = new Random();
        int index = r.nextInt(list.size());//指定范围
        int number = list.get(index);//得到指定的索引
        System.out.println(number);
        //5、创建两个集合添加男生和女生
        ArrayList<String> boyList = new ArrayList<>();
        ArrayList<String> girlList = new ArrayList<>();
        Collections.addAll(boyList,"b1","b2","b3","b4","b5");
        Collections.addAll(girlList,"g1","g2","g3","g4","g5");
        //6、获取被抽取的学生
        if(number == 1){
            int boyindex = r.nextInt(boyList.size());
            String name = boyList.get(boyindex);
            System.out.println(name);
        }else {
            int girlindex = r.nextInt(girlList.size());
            String name = girlList.get(girlindex);
            System.out.println(name);
        }
    }
}

集合练习2:随机点名(2)

需求:班级里有5个学生,开始随机点名,点到的同学不会被再次点到,共点名5轮

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Test3 {
    public static void main(String[] args) {
        //1、创建集合
        ArrayList<String> list = new ArrayList<>();
        ArrayList<String> list1 = new ArrayList<>();
        //2、添加元素
        Collections.addAll(list, "p1", "p2", "p3", "p4", "p5");
        int size = list.size();//获取集合中元素个数
        //3、开始随机点名
        for (int i = 1; i <= 5; i++) {
            System.out.println("第"+ i +"轮点名开始了");
            Random r = new Random();
            for (int j = 0; j < size; j++) {
                int index = r.nextInt(list.size());
                String name = list.get(index);
                list1.add(name);//集合中的元素添加到list1中
                System.out.println(name);//输出姓名
                list.remove(index);//点完名就删了
            }
            list.addAll(list1);//把list1的元素全部赋值给list
            list1.clear();//清空list1集合
        }
    }
}

集合练习3:斗地主(准备牌、洗牌、发牌、看牌)

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
public class PokerGame2 {
        //1、创建集合
        static HashMap<Integer, String> hm = new HashMap<>();
        static ArrayList<Integer> list = new ArrayList<>();//用来存储键值
        static {
            String[] color = {"♠", "♥", "♦", "♣"};
            String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
            //2、添加元素到集合
            int serialNumber = 1;
            for (String n : number) {//先添加遍历数字
                for (String c : color) {//再遍历颜色
                    hm.put(serialNumber, c + n);//添加序号(键)和牌(值)
                    list.add(serialNumber);
                    serialNumber++;
                }
            }
            //添加大王和小王
            hm.put(serialNumber, "小王");
            list.add(serialNumber);
            serialNumber++;
            hm.put(serialNumber, "大王");
            list.add(serialNumber);
            System.out.println(hm);
            System.out.println(list);
        }
    public PokerGame2() {
            //洗牌
            Collections.shuffle(list);
            //3、创建四个集合()
            TreeSet<Integer> lord = new TreeSet<>();
            TreeSet<Integer> player1 = new TreeSet<>();
            TreeSet<Integer> player2 = new TreeSet<>();
            TreeSet<Integer> player3 = new TreeSet<>();
            //发牌
            for (int i = 0; i < list.size(); i++) {
                int poker = list.get(i);
                if (i <= 2) {
                    lord.add(poker);
                    continue;
                }
                if (i % 3 == 0) {
                    player1.add(poker);
                } else if (i % 3 == 1) {
                    player2.add(poker);
                } else {
                    player3.add(poker);
                }
            }
            //看牌
            lookpoker("底牌", lord);
            lookpoker("玩家1", player1);
            lookpoker("玩家2", player2);
            lookpoker("玩家3", player3);
        }
        public void lookpoker (String name, TreeSet < Integer > ts){
            System.out.print(name + ": ");
            //遍历TreeSet集合得到每一个序号,再拿着序号去Map集合中去找真正的牌
            for (int serialNumber : ts) {
                String poker = hm.get(serialNumber);
                System.out.print(poker + " ");
            }
            System.out.println();
        }
}

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

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

相关文章

打破应用孤岛,iPaaS连接全域新协作

“据全球知名的咨询平台Garner分析&#xff0c;集成平台将在企业数字化转型过程中扮演重要的角色&#xff0c;企业内外应用的打通成为推动企业快速实现数字化转型的重要因素之一。SaaS 的井喷式发展也带来了新的机遇与挑战&#xff0c;企业亟需新的集成方法和手段帮助解决自身问…

吴恩达【神经网络和深度学习】Week4——深层神经网络

文章目录Deep Neural Network1、Deep L-layer Neural Network2、Forward Propagation in a Deep Network3、Getting your matrix dimensions right4、Why deep representations?5、 Building blocks of deep neural networks6、 Forward and Backward Propagation7、Parameter…

【Ctfer训练计划】——(十一)

作者名&#xff1a;Demo不是emo主页面链接&#xff1a; 主页传送门创作初心&#xff1a; 舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

最新版wifi营销分销流量主前后端+小程序源码+搭建教程

前端后端数据库搭建教程&#xff0c;无任何密码&#xff0c;亲测能用&#xff0c;避免踩坑&#xff0c;v&#xff1a;JZ716888 教程如下&#xff1a; 安装源码到根目录 1、网站运行目录public 2、PHP7.2&#xff0c;开通SSL 3、导入数据库文件 4、修改数据库文件里applic…

【十一】Netty UDP协议栈开发

Netty UDP协议栈开发介绍协议简介伪首部UDP协议的特点开发jar依赖UDP 服务端启动类服务端业务处理类客户端启动类客户端业务处理类代码说明测试服务端打印截图&#xff1a;客户端打印截图:测试结果总结介绍 UDP 是用户数据报协议(User Datagram Protocol) 的简称&#xff0c;其…

【Azure 架构师学习笔记】-Azure Logic Apps(4)-演示2

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Logic Apps】系列。 接上文[【Azure 架构师学习笔记】-Azure Logic Apps&#xff08;3&#xff09;-演示1] (https://blog.csdn.net/DBA_Huangzj/article/details/128542539) 前言 上文做了简单的演示&#xff0c;这一…

【Flutter】关于Button 的那些知识ElevatedButton等,以及Buttonstyle

文章目录前言一、Button是什么&#xff1f;二、开始使用button1.ElevatedButton1.无style 的ElevatedButton2.基础功能的处理之后的button3.利用buttonstyle 来美化下button2.IconButton&#xff0c;TextButton基础功能都是一样的三、做几个好看点的按键总结前言 一、Button是什…

【设计模式】七大设计原则

设计模式学习之旅(二) 查看更多可关注后查看主页设计模式DayToDay专栏 在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;程序员要尽量根据7条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成…

SAP 详细解析在建工程转固定资产

由固定资产归口采购部门或业务部门提交购置固定资产/在建工程的申请&#xff0c;经审批后&#xff0c;若是需要安装调试&#xff0c;则由财务部固定资产会计建立内部订单收集成本&#xff0c;月末结转在建工程。项目完工后&#xff0c;相关部门&#xff08;公司装备部、分公司装…

数据库设计之三范式

写在前面 很多数据库设计者&#xff0c;都是按照自己的性子和习惯来设计数据库数据表&#xff0c;其实不然。 其实&#xff0c;数据库的设计也有要遵循的原则。 范式&#xff0c;就是规范&#xff0c;就是指设计数据库需要&#xff08;应该&#xff09;遵循的原则。 每个范…

智慧变频中的数据监测、下发控制以及告警推送

[小 迪 导读]&#xff1a;在智能制造的推动下&#xff0c;制造商对于变频器在绿色节能、智能运行、远程维护以及大数据等方面的需求也日趋凸显。针对传统变频器无法满足智能时代的需求问题&#xff0c;dgiot可适配多种DTU/网关对变频器进行数据监测、下发控制以及告警推送。概述…

VS2019编译OSG

VS2019编译OSG 资源准备 由于3rd依赖项很多&#xff0c;编译耗时&#xff0c;可以在牛人编译的版本基础上开展。 杨石兴编译博客&#xff1b; 百度网盘&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/101IXFgvKQhQOEbfLa-ztZg 提取码&#xff1a;osgb 编译 1. 编译…

【patch-package】修改node_modules下的依赖包源码

场景&#xff1a;当项目里使用的element-ui有bug&#xff0c;但是项目里又急需修改这bug&#xff0c;这个时候就需要给依赖打补丁啦~ 1、patch-package 1.1、概念 lets app authors instantly make and keep fixes to npm dependencies. Its a vital band-aid for those of u…

【hcip】mpls实验

目录 1.拓扑图 2.要求 3.主要配置 4.测试 1.拓扑图 2.要求 实现全网可达 3.主要配置 isp区域已配置ospf&#xff0c;bgp 然后配置mpls&#xff08;r2&#xff09; r2]mpls lsr-id 2.2.2.2 [r2]mpls Info: Mpls starting, please wait... OK! [r2-mpls]mpls ld [r2-mpls…

VTK-vtkPolyData解读

小结&#xff1a;本博文主要讲解vtkPolyData接口及常用的方法实现原理。 vtkPolyData 1描述 vtkPolyData是一系列的数据集包括vertices&#xff0c;lines&#xff0c;polygons&#xff0c;triangle strips。 vtkPolyData是vtkDataSet的具体实现&#xff0c;代表了一系列的几…

ELF文件格式解析

ELF文件是什么&#xff1f; ELF是Executable and Linkable Format的缩写&#xff0c;字面上看就是可执行和可连接文件。在Linux下可重定位文件(.o)、可执行文件、共享目标文件(.so)、核心转储问文件(core dump) 都是使用ELF文件格式。 ELF 通常由编译器或者连接器产生&#x…

2021年大数据挑战赛B题口罩佩戴检测求解全过程论文及程序

2021年大数据挑战赛 B题 口罩佩戴检测 原题再现&#xff1a; 新冠疫情的爆发对人类生命安全及全球经济发展造成了重大影响。虽然现在国内疫情基本得到有效遏制&#xff0c;但日常防控仍不可松懈。戴口罩是预防新冠肺炎最便捷、最有效的措施和方法。人脸佩戴口罩的自动化识别可…

2022跨境支付回顾,iPayLinks让“链接”更高效

从2015年服务第一个客户开始iPayLinks已陪伴用户走过8个春秋作为贴心的跨境资金管家iPayLinks跨越山海&#xff0c;链接全球以产品为基石这一年&#xff0c;iPayLinks持续开发新产品、新功能&#xff0c;帮助外贸企业和跨境卖家抓住机遇&#xff0c;降本增效。B2B外贸收款主打“…

Python 使用TF-IDF

第一个 简易版本 直接来至 jieba 包&#xff0c; 一下代码直接来源 https://blog.csdn.net/qq_38923076/article/details/81630442 这里记录 进行对比 jieba.analyse.extract_tags(sentence, topK20, withWeightFalse, allowPOS()) sentence&#xff1a;待提取的文本语料 topK…

【阶段三】Python机器学习25篇:机器学习项目实战:LigthGBM算法的核心思想、原理与LightGBM分类模型

本篇的思维导图: LigthGBM算法的核心思想 LigthGBM算法是Boosting算法的新成员,由微软公司开发。它和XGBoost算法一样是对GBDT算法的高效实现,在原理上与GBDT算法和XGBoost算法类似,都采用损失函数的负梯度作为当前决策树的残差近似值,去拟合新的决策树。 …