Skip to content

集合

1 引用数据类型使用

1.1 使用方式

- 基本数据类型可以当做方法的参数,返回值及成员变量使用,传递或者保存的是数据值。
- 引用数据类型也可以当做方法的参数,返回值及字段使用,传递或者保存的是对象的引用(地址)。
- 特别要注意,如果是抽象类或者接口那么传递或者保存的就是子类对象的地址引用了
java
package com.fan.datatype_demo;


public interface Player {
    public abstract void play();
}

abstract class Mp3Player implements Player {

}

class IPod extends Mp3Player {
    @Override
    public void play() {
        System.out.println("IPod播放音乐...");
    }
}
java
package com.fan.datatype_demo;

/*
   1 分别定义含有Play,Mp3Player , Ipod参数的方法,并调用传入实参进行测试

   2  定义一个学生类,里面定义含有Player, Mp3Player,Ipod类型的成员变量
      创建学生对象并给成员变量赋值

 */
public class PlayerTest {
    public static void main(String[] args) {
        show1(new IPod());
        show2(new IPod());
        show2(new IPod());

        Student s = new Student();
        s.setPlayer(new IPod());
        s.setMp3Player(new IPod());
        s.setiPod(new IPod());
    }

    public static void show1(Player player) {// 方法的参数是一个接口 , 接收实现类对象
        player.play();
    }

    public static void show2(Mp3Player player) {// 方法的参数是一个抽象类 , 接收子类对象
        player.play();
    }

    public static void show3(Mp3Player player) {// 方法的参数是具体的类 , 接收此类对象或者子类对象
        player.play();
    }
}

/*
    定义一个学生类,里面定义含有Player, Mp3Player,Ipod类型的成员变量
    创建学生对象并给成员变量赋值
 */
class Student {
    private Player player;   // 接口的类型的成员变量 , 保存的是实现类对象地址
    private Mp3Player mp3Player; // 实现类的类型的成员变量 , 保存的是子类对象地址
    private IPod iPod; // 具体类类型的成员变量 , 保存的是此类对象或者此类的子类对象地址


    public Player getPlayer() {
        return player;
    }

    public void setPlayer(Player player) {
        this.player = player;
    }

    public Mp3Player getMp3Player() {
        return mp3Player;
    }

    public void setMp3Player(Mp3Player mp3Player) {
        this.mp3Player = mp3Player;
    }

    public IPod getiPod() {
        return iPod;
    }

    public void setiPod(IPod iPod) {
        this.iPod = iPod;
    }
}

2 Collection集合

2.1 集合和数组的区别

  • 长度区别
    • 数组 : 长度固定
    • 集合 : 长度可变
  • 存储数据类型
    • 数组 : 可以存储基本数据类型, 也可以存储引用数据类型
    • 集合 : 只能存储引用数据类型 , 要想存储基本数据类型 , 需要存储对应的包装类类型

2.2 集合的体系

image-20210404232635762

2.3 Collection集合常用的方法

  • 在学习集合体系,一般先学习顶层接口。学习了顶层接口的方法,子类型继承而来的方法,就可以不用重复学习。
    • public boolean add(E e): 把给定的对象添加到当前集合中 。
    • public void clear() :清空集合中所有的元素。
    • public boolean remove(E e): 把给定的对象在当前集合中删除。
    • public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
    • public boolean isEmpty(): 判断当前集合是否为空。
    • public int size(): 返回集合中元素的个数。
    • public Object[] toArray(): 把集合中的元素,存储到数组中

2.4 迭代器

  • 概述 :
    • 迭代器就是对Iterator的称呼 , 专门用来对Collection集合进行遍历使用的。学习迭代器的目的就是为了遍历集合
  • 注意 :
    • 只有继承/实现Iterable接口才具有迭代的能力
    • Collection接口继承了Iterable接口所以 , Collection及其子类都具备迭代的能力
  • 获取迭代器对象的方式
    • 通过Collection集合对象调用Iterable接口中的iterator方法 , 就可以获取迭代器对象
  • Iterator(迭代器)中的方法
    booleanhasNext()如果迭代具有更多元素,则返回 true 。
    Enext()返回迭代中的下一个元素。
    default voidremove()从底层集合中删除此迭代器返回的最后一个元素(可选操作)。
  • 迭代器的注意事项
    • 当迭代器迭代元素完成后,不能继续next获取元素,否则会报:NoSuchElementException
    • 当迭代器在使用的过程中,不能使用集合对象直接增删元素。会导致报错ConcurrentModificationException。如果要删除可以使用迭代器来删除

2.5 增强for循环

  • 增强for循环(foreach),专门用来遍历集合或者数组,底层实现使用迭代器

  • 定义格式 :

    java
    for(元素的类型 变量名 : 数组/单列集合 ){
        变量代表的就是集合或者数组的元素
    }

3 泛型

3.1 泛型的介绍

  • 泛型是一种类型参数,专门用来保存类型用的
    • 最早接触泛型是在ArrayList<E>,这个E就是所谓的泛型了。使用ArrayList时,只要给E指定某一个类型,里面所有用到泛型的地方都会被指定对应的类型

3.2 使用泛型的好处

  • 不用泛型带来的问题
    • 集合若不指定泛型,默认就是Object。存储的元素类型自动提升为Object类型。获取元素时得到的都是Object,若要调用特有方法需要转型,给我们编程带来麻烦.
  • 使用泛型带来的好处
    • 可以在编译时就对类型做判断,避免不必要的类型转换操作,精简代码,也避免了因为类型转换导致的代码异常
java
 //泛型没有指定类型,默认就是Object
ArrayList list = new ArrayList();
list.add("Hello");
list.add("World");
list.add(100);
list.add(false);
//集合中的数据就比较混乱,会给获取数据带来麻烦
for (Object obj : list) {
    String str = (String) obj;
    //当遍历到非String类型数据,就会报异常出错
    System.out.println(str + "长度为:" + str.length());
}

3.3 泛型的注意事项

  • 泛型在代码运行时,泛型会被擦除。后面学习反射的时候,可以实现在代码运行的过程中添加其他类型的数据到集合

    • 泛型只在编译时期限定数据的类型 , 在运行时期会被擦除

3.4 自定义泛型类

  • 当一个类定义其属性的时候,不确定具体是什么类型时,就可以使用泛型表示该属性的类型

  • 定义的格式
    • 在类型名后面加上一对尖括号,里面定义泛型。一般使用一个英文大写字母表示,如果有多个泛型使用逗号分隔
    • public class 类名<泛型名>
    java
    举例 : 
    public class Student<X,Y>{  
        X  xObj; 
    }
  • 泛型的确定
    • 当创建此泛型类是 , 确定泛型类中泛型的具体数据类型
  • 练习
java
package com.fan.genericity_demo.genericity_class;

import java.time.Period;

/*
    需求 : 定义一个人类,定义一个属性表示爱好,但是具体爱好是什么不清楚,可能是游泳,乒乓,篮球。
 */
public class GenericityDemo {
    public static void main(String[] args) {
        Person<BasketBall> person = new Person<>();
        person.setHobby(new BasketBall());

        Person<Swim> person2 = new Person<>();
        person2.setHobby(new Swim());

        Person person3 = new Person<>();// 如果没有指定泛型 , 那么默认使用Object数据类型
    }
}

class Person<H> {
    // 定义属性表达爱好
    private H hobby;


    public H getHobby() {
        return hobby;
    }

    public void setHobby(H hobby) {
        this.hobby = hobby;
    }
}

class Swim {
}

class PingPang {
}

class BasketBall {
}

3.5 自定义泛型接口

  • 当定义接口时,内部方法中其参数类型,返回值类型不确定时,就可以使用泛型替代了。

  • 定义泛型接口
    • 在接口后面加一对尖括号 , 尖括号中定义泛型 , 一般使用大写字母表示, 多个泛型用逗号分隔
    • public interface<泛型名>
    • 举例 :
    java
    public interface Collection<E>{
    	public boolean add(E e);
    }
  • 泛型的确定
    • 实现类去指定泛型接口的泛型
    • 实现了不去指定泛型接口的泛型 , 进行延续泛型 , 回到泛型类的使用
java
package com.fan.genericity_demo.genericity_interface;
/*
    需求:
    模拟一个Collection接口,表示集合,集合操作的数据不确定。
    定义一个接口MyCollection具体表示。

 */
// 泛型接口
public interface MyCollection<E> {
    // 添加功能
    public abstract void add(E e);
    // 删除功能
    public abstract void remove(E e);
}

// 指定泛型的第一种方式 : 让实现类去指定接口的泛型
class MyCollectionImpl1 implements MyCollection<String>{
    @Override
    public void add(String s) {

    }
    @Override
    public void remove(String s) {

    }
}
// 指定泛型的第二种方式 : 实现类不确定泛型,延续泛型,回到泛型类的使用
class MyCollectionImpl2<E> implements MyCollection<E>{

    @Override
    public void add(E a) {

    }

    @Override
    public void remove(E a) {

    }
}

3.6 自定义泛型方法

  • 当定义方法时,方法中参数类型,返回值类型不确定时,就可以使用泛型替代了

  • 泛型方法的定义
    • 可以在方法的返回值类型前定义泛型
    • 格式 : public <泛型名> 返回值类型 方法名(参数列表){ ... }
    • 举例 : public <T> void show(T t) { ... }
  • 泛型的确定
    • 当调用一个泛型方法 , 传入的参数是什么类型, 那么泛型就会被确定
  • 练习
    java
    package com.fan.genericity_demo.genericity_method;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class Test {
        public static void main(String[] args) {
            // Collection集合中 : public <T> T[] toArray(T[] a) : 把集合中的内容存储到一个数组中 , 进行返回
            ArrayList<String> list = new ArrayList<>();
            list.add("abc");
            list.add("ads");
            list.add("qwe");
            String[] array = list.toArray(new String[list.size()]);
            System.out.println(Arrays.toString(array));
        }
    
        // 接收一个集合 , 往集合中添加三个待指定类型的元素
        public static <X> void addElement(ArrayList<X> list, X x1, X x2, X x3) {
            list.add(x1);
            list.add(x2);
            list.add(x3);
        }
    }

3.7 通配符

  • 当我们对泛型的类型确定不了,而是表达的可以是任意类型,可以使用泛型通配符给定

    符号就是一个问号:? 表示任意类型,用来给泛型指定的一种通配值。如下

java
public static void shuffle(List<?> list){
   //…
} 

说明:该方法时来自工具类Collections中的一个方法,用来对存储任意类型数据的List集合进行乱序
  • 泛型通配符结合集合使用

    • 泛型通配符搭配集合使用一般在方法的参数中比较常见。在集合中泛型是不支持多态的,如果为了匹配任意类型,我们就会使用泛型通配符了。
    • 方法中的参数是一个集合,集合如果携带了通配符,要特别注意如下
      • 集合的类型会提升为Object类型
      • 方法中的参数是一个集合,集合如果携带了通配符,那么此集合不能进行添加和修改操作 , 可以删除和获取
    java
    package com.fan.genericity_demo;
    
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            list.add("abc");
            list.add("asd");
            list.add("qwe");
            // 方法的参数是一个集合 , 集合的泛型是一个通配符 , 可以接受任意类型元素的集合
            show(list);
        }
    
        public static void show(List<?> list) {
            // 如果集合的泛型是一个通配符 , 那么集合中元素以Object类型存在
            Object o = list.get(0);
    
            // 如果集合的泛型是一个通配符 , 那么此集合不能进行添加和修改操作 , 可以删除和获取
            // list.add(??);
    
            // 删除可以
            list.remove(0);
            // 获取元素可以
            for (Object o1 : list) {
                System.out.println(o1);
            }
        }
    }
    java
    package com.fan.genericity_demo;
    
    import java.util.ArrayList;
    
    /*
        已知存在继承体系:Integer继承Number,Number继承Object。
        定义一个方法,方法的参数是一个ArrayList。
        要求可以接收ArrayList<Integer>,ArrayList<Number>,ArrayList<Object>,ArrayList<String>这些类型的数据。
    
        结论 : 具体类型的集合,不支持多态 , 要想接收任意类型集合 , 需要使通配符集合
     */
    public class Test1 {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<>();
            ArrayList<Number> list2 = new ArrayList<>();
            ArrayList<String> list3 = new ArrayList<>();
            ArrayList<Object> list4 = new ArrayList<>();
    
            useList5(list1);
            useList5(list2);
            useList5(list3);
            useList5(list4);
        }
    
        // 此方法只能接收存储Integer类型数据的集合
        public static void useList1(ArrayList<Integer> list) {
    
        }
    
        // 此方法只能接收存储Number类型数据的集合
        public static void useList2(ArrayList<Number> list) {
    
        }
    
        // 此方法只能接收存储String类型数据的集合
        public static void useList3(ArrayList<String> list) {
    
        }
    
        // 此方法只能接收存储Object类型数据的集合
        public static void useList4(ArrayList<Object> list) {
    
        }
    
        public static void useList5(ArrayList<?> list) {
    
        }
    
    }

3.8 受限泛型

  • 受限泛型是指,在使用通配符的过程中 , 对泛型做了约束,给泛型指定类型时,只能是某个类型父类型或者子类型

  • 分类 :

    • 泛型的下限 :
      • <? super 类型> //只能是某一类型,及其父类型,其他类型不支持
    • 泛型的上限 :
      • <? extends 类型> //只能是某一个类型,及其子类型,其他类型不支持
    java
    package com.fan.genericity_demo.wildcard_demo;
    
    import java.util.ArrayList;
    
    /*
      wildcardCharacter
    
      基于上一个知识点,定义方法
        show1方法,参数只接收元素类型是Number或者其父类型的集合
        show2方法,参数只接收元素类型是Number或者其子类型的集合
    
     */
    public class Test2 {
        public static void main(String[] args) {
            ArrayList<Integer> list1 = new ArrayList<>();
            ArrayList<Number> list2 = new ArrayList<>();
            ArrayList<Object> list3 = new ArrayList<>();
    
            show1(list3);
            show1(list2);
    
            show2(list2);
            show2(list1);
        }
        // 此方法可以接受集合中存储的是Number或者Number的父类型 , 下限泛型
        public static void show1(ArrayList<? super Number> list) {
    
        }
        // 此方法可以接受集合中存储的是Number或者Number的子类型 , 上限泛型
        public static void show2(ArrayList<? extends Number> list) {
    
        }
    }

4 数据结构

  • 栈结构 : 先进后出

  • 队列结构 : 先进先出

  • 数组结构 : 查询快 , 增删慢

  • 链表结构 : 查询慢 , 增删快

  • 二叉树

    • 二叉树 : 每个节点最多有两个子节点

    • 二茬查找树 : 每个节点的左子节点比当前节点小 , 右子节点比当前节点大

    • 二茬平衡树 : 在查找树的基础上, 每个节点左右子树的高度不超过1

    • 红黑树 :

      • 每一个节点或是红色的,或者是黑色的

      • 根节点必须是黑色

      • 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

      • 不能出现两个红色节点相连的情况

      • 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

      • 添加元素 :

        image-20210405235529852

  • 哈希表结构 :

    • 哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
    • Object类中有一个方法可以获取对象的哈希值 public int hashCode():返回对象的哈希码值
    • 对象的哈希值特点
      • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
      • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

5 List集合

  • List集合是Collection集合子类型,继承了所有Collection中功能,同时List增加了带索引的功能

  • 特点 :
    • 元素的存取是有序的【有序】
    • 元素具备索引 【有索引】
    • 元素可以重复存储【可重复】
  • 常见的子类
    • ArrayList:底层结构就是数组【查询快,增删慢】
    • Vector:底层结构也是数组(线程安全,同步安全的,低效,用的就少)
    • LinkedList:底层是链表结构(双向链表)【查询慢,增删快】
  • List中常用的方法
    • public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
    • public E get(int index):返回集合中指定位置的元素
    • public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。\
    • public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素
  • LinkedList类
    • LinkedList底层结构是双向链表。每个节点有三个部分的数据,一个是保存元素数据,一个是保存前一个节点的地址,一个是保存后一个节点的地址。可以双向查询,效率会比单向链表高。
    • LinkedList特有方法
      • public void addFirst(E e):将指定元素插入此列表的开头。
      • public void addLast(E e):将指定元素添加到此列表的结尾。
      • public E getFirst():返回此列表的第一个元素。
      • public E getLast():返回此列表的最后一个元素。
      • public E removeFirst():移除并返回此列表的第一个元素。
      • public E removeLast():移除并返回此列表的最后一个元素。

6 Set集合

  • Set集合也是Collection集合的子类型,没有特有方法。Set比Collection定义更严谨
  • 特点 :
    • 元素不能保证插入和取出顺序(无序)
    • 元素是没有索引的(无索引)
    • 元素唯一(元素唯一)
  • Set常用子类
    • HashSet:底层由HashMap,底层结构哈希表结构。 去重,无索引,无序。 哈希表结构的集合,操作效率会非常高。
    • LinkedHashSet:底层结构链表加哈希表结构。 具有哈希表表结构的特点,也具有链表的特点。
    • TreeSet:底层是有TreeMap,底层数据结构 红黑树。 去重,让存入的元素具有排序(升序排序)

7 TreeSet集合

7.1 集合体系

  • Collection

    • List接口

      • ArrayList类
      • LinkedList类
    • Set接口

      • HashSet集合

      • TreeSet集合

7.2 TreeSet特点

  • 不包含重复元素的集合[元素唯一]
  • 没有带索引的方法[无索引]
  • 可以按照指定的规则进行排序[可以排序]

7.3 TreeSet集合的练习

java
package com.fan.treeset_demo;

import java.util.Iterator;
import java.util.TreeSet;

/*
      1 TreeSet集合练习
            存储Integer类型的整数,并遍历
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(10);
        ts.add(10);
        ts.add(20);
        ts.add(10);
        ts.add(30);

        // 迭代器
        Iterator<Integer> it = ts.iterator();
        while(it.hasNext()){
            Integer s = it.next();
            System.out.println(s);
        }

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

        // 增强for
        for (Integer t : ts) {
            System.out.println(t);
        }
    }
}
  • 如果TreeSet存储自定义对象 , 需要对自定义类进行指定排序规则

    下列代码没有指定排序规则 , 所以运行会报出错误

java
package com.fan.treeset_demo;

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 +
                '}';
    }
}
=============================================================
    
    
package com.fan.treeset_demo;

import java.util.Iterator;
import java.util.TreeSet;

/*
      TreeSet集合练习
         存储学生对象,并遍历

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

        Student s1 = new Student("dilireba", 19);
        Student s2 = new Student("gulinazha", 20);
        Student s3 = new Student("maerzhaha", 18);

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

        System.out.println(ts);
    }
}

7.4 排序规则

7.4.1 自然排序

  • 使用步骤
    • 使用空参构造创建TreeSet集合对象
    • 存储元素所在的类需要实现Comparable接口
    • 重写Comparable接口中的抽象方法 compareTo方法,指定排序规则
  • compareTo方法如何指定排序规则 :
    • 此方法如果返回的是小于0 , 代表的是当前元素较小 , 需要存放在左边
    • 此方法如果返回的是大于0 , 代表的是当前元素较大, 需要存放在右边
    • 此方法如果返回的是0 , 代表的是当前元素在集合中已经存在 , 不存储
  • 练习 : 存储学生对象, 按照年龄的升序排序,并遍历
    java
    package com.fan.treeset_demo;
    
    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) {
            /*
                this : 当前要添加的元素
                o    : 集合中已经存在的元素
    
                如果方法返回值为负数 : 当前元素放左边
                如果方法的返回值为正数  : 当前元素放右边
                如果方法的返回值为0  : 说明当前元素在集合中存在,不存储
             */
            int result = this.age - o.age;
            return result;
        }
    }
    =====================================================
        
    package com.fan.treeset_demo;
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /*
          TreeSet集合练习
             存储学生对象,并遍历
    
     */
    public class TreeSetDemo2 {
        public static void main(String[] args) {
            TreeSet<Student> ts = new TreeSet<>();
    
            Student s1 = new Student("dilireba", 19);
            Student s2 = new Student("gulinazha", 20);
            Student s3 = new Student("maerzhaha", 18);
    
            ts.add(s1);
            ts.add(s2);
            ts.add(s3);
    
            System.out.println(ts);
        }
    }
    • 对刚才的案例进行改进 , 如果年龄相等 , 那么对学生的名字在字典的顺序排序
    java
    package com.fan.treeset_demo;
    
    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) {
            /*
                this : 当前要添加的元素
                o    : 集合中已经存在的元素
    
                如果方法返回值为负数 : 当前元素放左边
                如果方法的返回值为正数  : 当前元素放右边
                如果方法的返回值为0  : 说明当前元素在集合中存在,不存储
             */
            int result = this.age - o.age;
            // 如果年龄相等 , 那么按照名字进行排序
            return result == 0 ? this.name.compareTo(o.name) : age;
        }
    }
    
    =============================================================
        
        
    package com.fan.treeset_demo;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /*
          TreeSet集合练习
             存储学生对象, 按照年龄的升序排序,并遍历
    
     */
    public class TreeSetDemo2 {
        public static void main(String[] args) {
            TreeSet<Student> ts = new TreeSet<>();
    
            Student s1 = new Student("dilireba", 19);
            Student s2 = new Student("gulinazha", 20);
            Student s3 = new Student("maerzhaha", 18);
            Student s4 = new Student("ouyangnanan", 18);
    
            ts.add(s1);
            ts.add(s2);
            ts.add(s3);
            ts.add(s4);
    
            System.out.println(ts);
        }
    }

7.4.2 比较器排序

  • 使用步骤
    • TreeSet的带参构造方法使用的是 “比较器排序” 对元素进行排序的
    • 比较器排序,就是让TreeSet集合构造方法接收Comparator接口的实现类对象
    • 重写Comparator接口中的 compare(T o1,T o2)方法 , 指定排序规则
    • 注意 : o1代表的是当前往集合中添加的元素 , o2代表的是集合中已经存在的元素,排序原理与自然排序相同!
  • 排序规则
    • 排序原理与自然排序相同!
  • 练习
java
package com.fan.treeset_demo.comparator_demo;

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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
======================================
    
package com.fan.treeset_demo.comparator_demo;

import java.util.Comparator;
import java.util.TreeSet;

/*
      TreeSet集合练习
         存储学生对象, 按照年龄的升序排序,并遍历

 */
public class TreeSetDemo2 {
    public static void main(String[] args) {
        TreeSet<Teacher> ts = new TreeSet<>(new ComparatorImpl());

        Teacher s1 = new Teacher("dilireba", 19);
        Teacher s2 = new Teacher("gulinazha", 20);
        Teacher s3 = new Teacher("maerzhaha", 18);
        Teacher s4 = new Teacher("ouyangnanan", 18);

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

        System.out.println(ts);
    }
}

// 比较器排序
class ComparatorImpl implements Comparator<Teacher> {
    @Override
    public int compare(Teacher o1, Teacher o2) {
        int result = o1.getAge() - o2.getAge();
        return result == 0 ? o1.getName().compareTo(o2.getName()) : result;
    }
}

7.4.3 两种排序的区别

  • 自然排序:自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序。

  • 比较器排序:创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序。

  • 如果Java提供好的类已经定义了自然排序排序规则 , 那么我们可以使用比较器排序进行替换

  • 注意 : 如果自然排序和比较器排序都存在 , 那么会使用比较器排序

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

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

8 Collections单列集合工具类

  • Collections工具类介绍
    • java.util.Collections 是集合的工具类,里面提供了静态方法来操作集合,乱序,排序....

8.1 shuffle方法

  • public static void shuffle(List<?> list) 对集合中的元素进行打乱顺序。

  • 集合中元素类型可以任意类型

    java
    package com.fan.collections_demo;
    
    import java.util.ArrayList;
    import java.util.Collections;
    
    /*
        Collections类 : 操作单列集合的工具类
            public static void shuffle(List<?> list) 对集合中的元素进行打乱顺序
            1 乱序只能对List集合进行乱序
            2 集合中元素类型可以任意类型
    
            需求 : 定义一个List集合,里面存储若干整数。对集合进行乱序
     */
    public class ShuffleDemo {
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(10);
            list.add(30);
            list.add(50);
            list.add(40);
            list.add(20);
    
            Collections.shuffle(list);
    
            System.out.println(list);// 打印集合中的元素
        }
    }

8.2 sort方法

  • public static <T extends Comparable> void sort (List<T> list): 对集合中的元素自然排序

    • 该方法只能对List集合进行排序
    • 从方法中泛型分析可知,集合中元素类型必须是Comparable的子类型
    java
    package com.fan.collections_demo;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    /*
        Collections类 : 单列集合的工具类
            sort方法是一个重载的方法,可以实现自然排序及比较器排序。
            要特别注意的是sort方法只能对List集合进行排序,方法如下:
    
            `public static <T extends Comparable> void sort (List<T> list)`
    
            练习:定义List集合,存储若干整数,进行排序
     */
    public class SortDemo1 {
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(3);
            list.add(2);
            list.add(4);
            list.add(1);
    
            // 使用此方法 , 需要集合中存储的元素实现Comparable接口
            Collections.sort(list);
    
            System.out.println(list);
        }
    }
  • public static <T> void sort (List<T> list, Comparator<? super T> c)

    • 方法只能对List集合排序

    • 对元素的类型没有要求

    • 需要定义一个比较器Comparator (规则和之前TreeSet时一样)

    • 使用场景:

      • List集合中的元素类型不具备自然排序能力(元素类型没有实现结果 Comparable)
      • List集合中的元素类型具备自然排序能力,但是排序规则不是当前所需要的。
      java
      package com.fan.collections_demo;
      
      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.Comparator;
      
      /*
          Collections类 : 单列集合的工具类
              sort方法是一个重载的方法,可以实现自然排序及比较器排序。
              要特别注意的是sort方法只能对List集合进行排序,方法如下:
      
              `public static <T extends Comparable> void sort (List<T> list)` : 只能对集合中的元素自然排序
      
              需求1:定义一个List集合,存储若干整数,要求对集合进行降序排序
              分析:整数类型Integer具备自然排序能力,但是题目要求降序排序
      
              需求2:定义一个学生类,属性有姓名,年龄。创建若干对象放到List集合中。要求对List集合中学生对象进行年龄的升序排序。
              分析:自定义类型默认是没有自然排序能力的,我们使用自定义比较器方式排序。
      
      
       */
      public class SortDemo2 {
          public static void main(String[] args) {
      
              /*
                  需求2:定义一个学生类,属性有姓名,年龄。创建若干对象放到List集合中。要求对List集合中学生对象进行年龄的升序排序。
                  分析:自定义类型默认是没有自然排序能力的,我们使用自定义比较器方式排序
              */
              ArrayList<Student> list = new ArrayList<>();
              list.add(new Student("lisi", 24));
              list.add(new Student("zhangsan", 23));
      
              Collections.sort(list, new Comparator<Student>() {
                  @Override
                  public int compare(Student o1, Student o2) {
                      return o1.getAge() - o2.getAge();
                  }
              });
              System.out.println(list);
          }
      
          /*
              需求1:定义一个List集合,存储若干整数,要求对集合进行降序排序
              分析:整数类型Integer具备自然排序能力,但是题目要求降序排序
           */
          private static void method1() {
              ArrayList<Integer> list = new ArrayList<>();
              list.add(3);
              list.add(2);
              list.add(4);
              list.add(1);
      
              // 使用此方法 , 需要集合中存储的元素实现Comparable接口
              Collections.sort(list, new Comparator<Integer>() {
                  @Override
                  public int compare(Integer o1, Integer o2) {
                      return o2 - o1;
                  }
              });
      
              System.out.println(list);
          }
      }

9 可变参数

9.1 可变参数介绍

  • 在 JDK5 中提供了可变参数,允许在调用方法时传入任意个参数。可变参数原理就是一个数组形式存在
  • 格式 : 修饰符 返回值类型 方法名(数据类型… 变量名)
  • 举例 : public void show(int ... num) : 表达式该方法可以接收任意个整数值 , 原理 : 其实就是一个int类型的数组

9.2 可变参数注意

  • 可变参数只能作为方法的最后一个参数,但其前面可以有或没有任何其他参数。
  • 可变参数本质上是数组,不能作为方法的重载。如果同时出现相同类型的数组和可变参数方法,是不能编译通过的。

9.3 可变参数的使用

  • 调用可变参数方法,可以给出零到任意多个参数,编译器会将可变参数转化为一个数组,也可以直接传递一个数组。 方法内部使用时直接当做数组使用即可
java
package com.fan.changevariable_demo;

/*
    1 什么是可变参数
        JDK5中,允许在调用方法时传入任意个参数。可变参数原理就是一个数组形式存在
        格式 : 修饰符 返回值类型 方法名(数据类型… 变量名) {  }
        举例 : public void show(int... num){}

    2 可变参数注意 :
        1) 可变参数只能作为方法的最后一个参数,但其前面可以有或没有任何其他参数。
        2) 可变参数本质上是数组,不能作为方法的重载。如果同时出现相同类型的数组和可变参数方法,是不能编译通过的。

    3 可变参数的使用 :
        调用可变参数的方法 , 可以传入0个到任意个数据 , 编译器会将可变参数转换成一个数组 , 也可以直接传递一个数组
        方法中把可变参数当做一个数组去使用即可


    练习:定义方法可以求任意个整数的和

 */
public class VariableDemo1 {
    public static void main(String[] args) {
        sum();
        sum(1, 2);
        sum(1, 2, 3, 4);
    }
    
    public static void sum(int... num) {// 方法的参数是一个int类型的可变参数
        int sum = 0;// 定义求和变量
        for (int i : num) {
            sum += i;
        }
        System.out.println(sum);
    }
}

9.4 addAll方法

  • static <T> boolean addAll(Collection<? super T> c , T... elements) : 添加任意多个数据到集合中

    • 该方法就是一个含有可变参数的方法,使用时可以传入任意多个实参,实用方便!

    • 分析 : Collection<? super T> , ? 可以是 T 的类型或者父类型 , 反过来 , T是?类型或者子类型

      那么当你确定?的类型,也就是集合的类型 , 就可以往集合中添加此类型或者子类型

    java
    package com.fan.changevariable_demo;
    
    import java.util.ArrayList;
    import java.util.Collections;
    
    /*
        Collections的addAll方法
            `static <T> boolean  addAll(Collection<? super T> c , T... elements)` : 添加任意多个数据到集合中
            分析: 该方法就是一个含有可变参数的方法,使用时可以传入任意多个实参,实用方便!
    
            练习:创建一个List集合,使用addAll方法传入若干字符串
    
     */
    public class VariableDemo2 {
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            Collections.addAll(list, 10, 20, 30, 40);
            System.out.println(list);// [10, 20, 30, 40]
        }
    }

10 Map集合

10.1 Map集合的介绍

  • java.util.Map<K,V> 集合,里面保存的数据是成对存在的,称之为双列集合。存储的数据,我们称为键值对。 之前所学的Collection集合中元素单个单个存在的,称为单列集合

10.2 特点

  • Map<K,V> K:键的数据类型;V:值的数据类型

  • 特点 :

    • 键不能重复,值可以重复
    • 键和值是 一 一 对应的,通过键可以找到对应的值
    • (键 + 值) 一起是一个整体 我们称之为“键值对” 或者 “键值对对象”,在Java中叫做“Entry对象”
  • 使用场景

    • 凡是要表示一一对应的数据时就可以Map集合
      • 举例 : 学生的学号和姓名 --- (fan001 小智)
      • 举例 : 夫妻的关系 ---- (王宝强 马蓉 ) (谢霆锋 张柏芝)

10.3 常用实现类

  • HashMap:
    • 此前的HashSet底层实现就是HashMap完成的,HashSet保存的元素其实就是HashMap集合中保存的键,底层结构是哈希表结构,具有键唯一,无序,特点。
  • LinkedHashMap:
    • 底层结构是有链表和哈希表结构,去重,有序
  • TreeMap:
    • 底层是有红黑树,去重,通过键排序

10.4 常用的方法

  • public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  • public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  • public V get(Object key): 根据指定的键,在Map集合中获取对应的值。
  • public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  • public boolean containKey(Object key): 判断该集合中是否有此键。
java
package com.fan.map_demo.mapmethod_demo;

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

/*
    Map中常用方法 :
        public V put(K key, V value):  把指定的键与指定的值添加到Map集合中
        public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值
        public V get(Object key) 根据指定的键,在Map集合中获取对应的值
        public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中
        public boolean containKey(Object key): 判断该集合中是否有此键。

     需求 : 将以下数据保存到Map集合中 , 进行测试以上方法
        “文章“       "马伊琍
        “谢霆锋”     “王菲”
        “李亚鹏”     “王菲”

 */
public class MapDemo {
    public static void main(String[] args) {
        //  创建双列集合对象
        Map<String, String> hm = new HashMap<>();

        // 添加元素
        // public V put(K key, V value):  把指定的键与指定的值添加到Map集合中
        hm.put("文章", "马伊琍");
        hm.put("谢霆锋", "王菲");
        hm.put("李亚鹏", "王菲");

        // public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值
        // System.out.println(hm.remove("谢霆锋"));

        // public V get(Object key) 根据指定的键,在Map集合中获取对应的值
        // System.out.println(hm.get("李亚鹏"));

        // public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中
//        Set<String> set = hm.keySet();
//        for (String key : set) {
//            System.out.println(key);
//        }

        // public boolean containKey(Object key): 判断该集合中是否有此键。
        // System.out.println(hm.containsKey("李亚鹏"));

        System.out.println(hm);// 打印集合 , 打印的是集合中的元素
    }
}

10.5 Map集合的遍历

  • 第一种方式 : 键找值
java
package com.fan.map_demo.map_test;


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

/*
    创建Map集合对象 , 往集合中添加以下四对元素 , 使用键找值遍历集合
    周瑜 -- 小乔
    孙策 -- 大乔
    刘备 -- 孙尚香
    诸葛亮 -- 黄月英
 */
public class MapTest1 {
    public static void main(String[] args) {
        // 创建集合对象
        Map<String, String> hm = new HashMap<>();

        // 添加元素
        hm.put("周瑜", "小乔");
        hm.put("孙策", "大乔");
        hm.put("刘备", "孙尚香");
        hm.put("诸葛亮", "黄月英");
    
        // 获取健集合
        Set<String> set = hm.keySet();
        
        // 遍历健集合 , 通过键找值
        for (String key : set) {
            String value = hm.get(key);
            System.out.println(key + "---" + value);
        }
    }
}
  • 第二种方式 : 获取键值对对象 , 在找到键和值
java
package com.fan.map_demo.map_test;

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

/*
    需求 :  创建Map集合对象 , 往集合中添加以下三对元素
            使用获取Entry对象集合,在找到键和值 遍历集合

        张无忌 -- 赵敏
        张翠山 -- 殷素素
        张三丰 -- 郭芙

 */
public class MapTest2 {
    public static void main(String[] args) {
        // 创建集合对象
        Map<String, String> hm = new HashMap<>();

        // 添加元素
        hm.put("张无忌", "赵敏");
        hm.put("张翠山", "殷素素");
        hm.put("张三丰", "郭芙");

        // 获取键值对对象集合
        Set<Map.Entry<String, String>> set = hm.entrySet();

        // 遍历键值对对象集合 , 获取每一个键值对对象
        for (Map.Entry<String, String> entry : set) {
            // 通过entry对象获取键
            String key = entry.getKey();
            // 通过entry对象获取值
            String value = entry.getValue();
            System.out.println(key + "--" + value);
        }
    }
}

10.6 HashMap集合

  • 注意 : HashMap集合 , 要想保证键唯一 , 那么键所在的类必须重写hashCode和equals方法
java
package com.fan.map_demo.map_test;

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 +
                '}';
    }
}
java
package com.fan.map_demo.map_test;
import java.util.HashMap;
import java.util.Set;

/*
    HashMap类 :
        存储数据,每位学生(姓名,年龄)都有自己的家庭住址。
        学生和地址有对应关系,将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。
        要求:学生姓名相同并且年龄相同视为同一名学生,不能重复存储
 */
public class HashMapTest {
    public static void main(String[] args) {
        // 学生作为键, 家庭住址作为值。
        HashMap<Student, String> hm = new HashMap<>();

        hm.put(new Student("迪丽热巴", 18) , "新疆");
        hm.put(new Student("迪丽热巴", 18) , "中国");

        Set<Student> set = hm.keySet();
        for (Student key : set) {
            String value = hm.get(key);
            System.out.println(key + "--" + value);
        }
    }
}

10.7 LinkedHashMap集合

  • LinkedHashMap类 , 在最底层采用的数据结构 : 是链表+哈希表。
  • 特点 :
    • 元素唯一
    • 元素有序
java
package com.fan.map_demo.map_test;

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

/*
    LinkedHashMap类 , 在最底层采用的数据结构 : 是链表+哈希表。
    特点 :
        1 元素唯一
        2 有序

    需求 : 创建LinkedHashMap对象 , 添加元素进行验证 元素唯一 , 有序的特点
 */
public class LinkedHashMapTest {
    public static void main(String[] args) {
        // 创建集合对象
        LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<>();

        linkedHashMap.put(1, "张三");
        linkedHashMap.put(1, "李四");
        linkedHashMap.put(2, "王五");
        linkedHashMap.put(3, "赵六");

        System.out.println(linkedHashMap);
    }
}

10.8 TreeMap集合

  • TreeMap的底层是红黑树实现的,有排序的能力,键去重。

  • 可以自然排序(键所在的类要实现Comparable)

  • 若自定义类没有自然排序功能,或自然排序功能不满足要求时。可以自定义比较器排序(Comparator)

java
package com.fan.map_demo.map_test;
import java.util.TreeMap;

/*
    需求 :
        定义TreeMap集合存储键值对,键使用Integer,值使用String,存储若干键值对,遍历集合观察结果是否有排序。
 */
public class TreeMapTest1 {
    public static void main(String[] args) {
        //  定义TreeMap集合存储键值对,键使用Integer,值使用String
        // 创建集合对象
        TreeMap<Integer, String> treeMap = new TreeMap<>();

        treeMap.put(1, "张三");
        treeMap.put(3, "赵六");
        treeMap.put(2, "王五");

        System.out.println(treeMap);
    }
}
java
package com.fan.map_demo.map_test;

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

/*
    需求:创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String)。
    学生属性姓名和年龄, 要求按照年龄进行升序排序并遍历
 */
public class TreeMapTest2 {
    public static void main(String[] args) {
        // 学生作为键, 家庭住址作为值。
        TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });

        tm.put(new Student("迪丽热巴", 18), "新疆");
        tm.put(new Student("迪丽热巴", 16), "中国");

        System.out.println(tm);
    }
}

11 集合嵌套

11.1 List嵌套List

java
package com.fan.Collection_nested_demo;

import java.util.ArrayList;
import java.util.List;

/*
    使用场景举例:一年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,保存一个年级所有的班级信息

    思路:
    可以使用List集合保存一个班级的学生
    可以使用List集合保存所有班级

    因此我们可以定义集合如下:
    班级:List<String>
        举例 :
            List<String> 三年一班 = {迪丽热巴 , 古力娜扎 ,马尔扎哈 ,欧阳娜娜}
            List<String> 三年二班 = {李小璐 , 白百何 , 马蓉}
            List<String> 三年三班 = {林丹 ,文章, 陈赫}

    年级:List<List<String>>
        举例 :
            List<List<String>> 年级 = {三年一班 , 三年二班 , 三年三班}
 */
public class Test3 {
    public static void main(String[] args) {
        List<String> 三年一班 = new ArrayList<>();
        三年一班.add("迪丽热巴");
        三年一班.add("古力娜扎");
        三年一班.add("马尔扎哈");
        三年一班.add("欧阳娜娜");

        List<String> 三年二班 = new ArrayList<>();
        三年二班.add("李小璐");
        三年二班.add("白百何");
        三年二班.add("马蓉");

        List<String> 三年三班 = new ArrayList<>();
        三年三班.add("林丹");
        三年三班.add("文章");
        三年三班.add("陈赫");

        List<List<String>> 年级 = new ArrayList<>();
        年级.add(三年一班);
        年级.add(三年二班);
        年级.add(三年三班);

        for (List<String> 班级 : 年级) {
            for (String name : 班级) {
                System.out.println(name);
            }
            System.out.println("-----------------");
        }
    }
}

11.2 List嵌套Map

java
package com.fan.Collection_nested_demo;

import java.util.*;

/*
    List嵌套Map :

    使用场景举例:一年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,姓名有与之对应的学号,保存一年级所有的班级信息。

    思路:
        1 可以使用Map集合保存一个班级的学生(键是学号,值是名字)
        2 可以使用List集合保存所有班级

    因此我们可以定义集合如下:

    班级:Map<String,String> 键是学号,值是姓名
        举例 :
            Map<String,String> 三年一班 = {it001 = 迪丽热巴 , it002 = 古力娜扎 ,it003 = 马尔扎哈 ,it004 = 欧阳娜娜}
            Map<String,String> 三年二班 = {it001 = 李小璐 , it002 = 白百何 , it003 = 马蓉}
            Map<String,String> 三年三班 = {it001 = 林丹 ,it002 = 文章, it003 = 陈赫}

    年级:List<Map<String,String>>保存每个班级的信息
        举例 :
              List<Map<String,String>> 年级 = {三年一班 , 三年二班 , 三年三班}
 */
public class Test2 {
    public static void main(String[] args) {
        Map<String, String> 三年一班 = new HashMap<>();
        三年一班.put("it001", "迪丽热巴");
        三年一班.put("it002", "古力娜扎");
        三年一班.put("it003", "马尔扎哈");
        三年一班.put("it004", "欧阳娜娜");


        Map<String, String> 三年二班 = new HashMap<>();
        三年二班.put("it001", "李小璐");
        三年二班.put("it002", "白百何");
        三年二班.put("it003", "马蓉");

        Map<String, String> 三年三班 = new HashMap<>();
        三年三班.put("it001", "林丹");
        三年三班.put("it002", "文章");
        三年三班.put("it003", "陈赫");


        List<Map<String, String>> 年级 = new ArrayList<>();
        年级.add(三年一班);
        年级.add(三年二班);
        年级.add(三年三班);

        for (Map<String, String> 班级 : 年级) {
            Set<String> studentId = 班级.keySet();
            for (String id : studentId) {
                String name = 班级.get(id);
                System.out.println(id + "---" + name);
            }
            System.out.println("=================");
        }
    }
}

11.3 Map嵌套Map

java
package com.fan.Collection_nested_demo;

import java.util.*;

/*
    Map嵌套Map

    使用场景举例:一个年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,姓名有与之对应的学号,保存一年级所有的班级信息,班级有与之对应的班级名称。

    思路:
    可以使用Map集合保存一个班级的学生(键是学号,值是名字)

    可以使用Map集合保存所有班级(键是班级名称,值是班级集合信息)

    因此我们可以定义集合如下:
    班级: Map<String,String> 键:学号,值:姓名
        举例 :
            Map<String,String> 三年一班 = {it001 = 迪丽热巴 , it002 = 古力娜扎 ,it003 = 马尔扎哈 ,it004 = 欧阳娜娜}
            Map<String,String> 三年二班 = {it001 = 李小璐 , it002 = 白百何 , it003 = 马蓉}
            Map<String,String> 三年三班 = {it001 = 林丹 ,it002 = 文章, it003 = 陈赫}

    年级: Map<String , Map<String,String>> 键:班级名称,值:具体班级信息
        举例:
            Map<String, Map<String,String>> 年级 = {"三年一班" = 三年一班 , "三年二班" = 三年二班 , "三年三班" = 三年三班 }

 */
public class Test3 {
    public static void main(String[] args) {

        Map<String, String> 三年一班 = new HashMap<>();
        三年一班.put("it001", "迪丽热巴");
        三年一班.put("it002", "古力娜扎");
        三年一班.put("it003", "马尔扎哈");
        三年一班.put("it004", "欧阳娜娜");


        Map<String, String> 三年二班 = new HashMap<>();
        三年二班.put("it001", "李小璐");
        三年二班.put("it002", "白百何");
        三年二班.put("it003", "马蓉");

        Map<String, String> 三年三班 = new HashMap<>();
        三年三班.put("it001", "林丹");
        三年三班.put("it002", "文章");
        三年三班.put("it003", "陈赫");


        Map<String, Map<String, String>> 年级 = new HashMap<>();
        年级.put("三年一班", 三年一班);
        年级.put("三年二班", 三年二班);
        年级.put("三年三班", 三年三班);

        Set<String> 班级名字集合 = 年级.keySet();

        for (String 班级名字 : 班级名字集合) {
            Map<String, String> 班级信息 = 年级.get(班级名字);
            Set<String> 学生学号 = 班级信息.keySet();
            for (String 学号 : 学生学号) {
                String 姓名 = 班级信息.get(学号);
                System.out.println("班级名字:" + 班级名字 + " ,学号:" + 学号 + " , 名字:" + 姓名);
            }
            System.out.println("============");
        }

    }
}

12 斗地主案例

java
package com.fan.javasecollection.doudizhu;

import java.util.*;

public class Test1 {
    public static void main(String[] args) {
        //Map集合:存储扑克牌的牌面值和编号
        Map<Integer, String> pokerMap = new HashMap<>();
        //List集合: 存放扑克牌的编号
        List<Integer> pokerNumber = new ArrayList<>();

        //功能1:准备牌
        int index = 0;//初始化扑克牌编号
        pokerMap.put(index, "大王");//添加扑克牌编号和牌面值
        pokerNumber.add(index);//添加扑克牌编号
        index++;
        pokerMap.put(index, "小王");
        pokerNumber.add(index);
        index++;
        String[] colors = {"♠", "♥", "♣", "♦"};
        String[] numbers = {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};
        for (String number : numbers) {
            for (String color : colors) {
                pokerMap.put(index, color + number);//添加扑克牌编号和牌面值
                pokerNumber.add(index);//添加扑克牌编号
                index++;//修改扑克牌编号
            }
        }
        System.out.println(pokerMap);
        System.out.println(pokerNumber);

        //功能2:洗牌(就是要打乱 扑克牌编号 顺序)
        Collections.shuffle(pokerNumber);
        //       System.out.println(pokerNumber);


        //功能3:发牌(给玩家发的是扑克牌编号)
        /* 扑克牌编号(List集合) : 21, 32, 44, 2, 28, 51, 1, 45, 29, 19, 16, 4,..........
                                  0   1   2   3  4   5   。。。。。。。。。。。。。
           玩家1:  21, 2        索引:0、3 、6          索引值%3==0
           玩家2:  32, 28       索引:1、4 、7          索引值%3==1
           玩家3:  44, 51       索引:2、5 、8          索引值%3==2

           底牌:   索引值>50
        */
        TreeSet<Integer> player1 = new TreeSet<>();
        TreeSet<Integer> player2 = new TreeSet<>();
        TreeSet<Integer> player3 = new TreeSet<>();
        TreeSet<Integer> dp = new TreeSet<>();//底牌

        //注意:使用普通for循环遍历pokerNumber集合
        for (int i = 0; i < pokerNumber.size(); i++) {
            //使用索引值对3进行取模运算
            if (i > 50) {
                //是底牌:扣留
                dp.add(pokerNumber.get(i));
            } else if(i % 3 == 0){
                player1.add(pokerNumber.get(i));
            }else if (i % 3 == 1) {
                player2.add(pokerNumber.get(i));
            } else if (i % 3 == 2) {
                player3.add(pokerNumber.get(i));
            }
        }
//        System.out.println(player1);
//        System.out.println(player2);
//        System.out.println(player3);
//        System.out.println(dp);


        //功能4:看牌
        lookPoker("小乔", player1, pokerMap);
        lookPoker("大乔", player2,pokerMap);
        lookPoker("黄月英", player3, pokerMap);
        lookPoker("底牌", dp,pokerMap);

    }

    /**
     * 看牌功能
     * @param name     玩家名字
     * @param treeSet  玩家手中的扑克牌编号
     * @param pokerMap  扑克牌集合(扑克牌编号、扑克牌面值)
     */
    public static void lookPoker(String name , TreeSet<Integer> treeSet , Map<Integer, String> pokerMap){
        System.out.println(name+"手中的扑克牌:");
        //遍历:Set集合(取出每一个扑克牌编号,通过编号,获取具体的扑克牌面值)
        for (Integer pokerNum : treeSet) {
            String poker = pokerMap.get(pokerNum);
            System.out.print( poker +"   ");
        }
        System.out.println("\n-----------------------------------------------------------------------------------");
    }
}

Released under the MIT License.