java集合Set-HashSet-LinkedHashSet-TreeSet-

文章目录

    • ==Set集合==
      • 概述
    • ==哈希值==
      • 概述
      • 案例:验证hashCode方法特点
    • ==数据结构之哈希表==
      • 概述
      • 哈希表的存储过程
      • 案例 HashSet集合存储学生对象并遍历
    • ==HashSet集合==
      • 概述
      • HashSet集合保证元素唯一性的源码分析
    • ==LinkedHashSet集合==
      • 概述
      • 案例:证明有序性和唯一性
    • ==TreeSet集合==
      • 概述
      • TreeSet类的clone方法
      • TreeSet是基于红黑树实现的
        • 案例:集合存储基本类型包装类
      • 自然排序Comparable使用
        • 案例:集合元素学生对象,排序年龄从小到大,姓名字母顺序
      • 比较器排序Comparator的使用
        • 案例1:学生按照年龄排序。
        • 案例2:成绩排序
        • 案例3:不重复的随机数

Set集合

概述

  • Set集合位于软件包java.util下,使用时需要导包
  • interface Set< E > E是泛型,表示set集合中元素的类型
  • Set集合继承于Collection集合,它没有特殊的方法,所有方法都来自于Collection
  • 特点:
    Set集合不包含重复元素;
    没有带索引的方法,所以不能使用普通for循环遍历
  • 创建Set集合对象,因为Set是接口,不能直接被实例化,所以需要采用实现类创建对象,实现类有HashSet、TreeSet、LinkedHashSet;
  • HashSet实现了Set接口,底层由哈希表支持,对集合的迭代顺序不作任何保证,不能保证集合在一段时间内保持不变
  • set集合是无序的,底层实现是map;

备注2022/6/3
底层由哈希表实现,对集合的迭代顺序不作任何保证,即哈希表存入内容顺序与输出内容顺序不一致;

案例:

// 216-test2
public class SetDemo {
    public static void main(String[] args){
        //创建集合对象
        Set<String> sArray = new HashSet<String>();

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

        
        sArray.add("world");
        //输出结果没有 两个world,说明Set集合不能有重复元素
        for (String s : sArray){
            System.out.println(s);
        }
        //输出内容是:java
        //world
        //hello
        // 表示Set集合不保证迭代顺序
    }
}

哈希值

概述

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

案例:验证hashCode方法特点

// 216-test2
public class HashDemo {
    public static void main(String[] args){
        Student s1 = new Student("汪苏泷",33);

        //相同对象的哈希值是相同的
        System.out.println(s1.hashCode());
        System.out.println(s1.hashCode());//460141958

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

        Student s2 = new Student("许嵩",36);
        //默认情况下 不同对象的哈希值是不同的
        System.out.println(s2.hashCode());//1163157884

        // Student类重写了hashCode方式后,输出的哈希值会相同

        //测试常用字符串的哈希值
        System.out.println("hello".hashCode());//99162322
        System.out.println("java".hashCode());//3254818
        System.out.println("world".hashCode());//113318802
        System.out.println("--------------");
        System.out.println("阳泉".hashCode());//1219830
        System.out.println("西安".hashCode());//1114602
        System.out.println("-------------");
        System.out.println("重地".hashCode());//1179395
        System.out.println("通话".hashCode());//1179395
        //视频中讲解这个是因为String重写了hashCode方法导致字符串哈希值一样,但是我认为不是,而是字符串重地和通话内部计算哈希值正好一样。
    }
}

数据结构之哈希表

概述

  • JDK8之前,底层采用数组+链表实现,也就是一个元素为链表的数组
  • JDK8以后,在长度比较长的时候,底层实现了优化,采用红黑树的形式
  • 根据hashSet的无参构造方法,哈希表的默认长度是16

哈希表的存储过程

  • 计算存入元素的哈希值,哈希表的默认长度是16,则编号是从0-15
  • 如何存储计算的哈希值呢?需要计算存储位置。将各哈希值对16取余,得到的结果为0-15之间的数,将对应的哈希值存入到哈希表中对应的编号中(0-15)
  • 如果计算的存储位置相同,则现在要存入的元素要与已经存在元素进行比较:①比较哈希值,不相同存储,相同再次比较;②比较哈希值的内容,相同不存储,不相同存储。

存储过程图:
java集合Set-HashSet-LinkedHashSet-TreeSet-_第1张图片

案例 HashSet集合存储学生对象并遍历

需求:
创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合

要求:
学生对象的成员变量值相同,我们就认为是同一个对象

关于要求涉及到重写hashcode方法和equals方法

// 216-test2
public class HashSetDemo {
    public static void main(String[] args){

        HashSet<Student> hs = new HashSet<Student>();

        Student s1 = new Student("汪苏泷",33);
        Student s2 = new Student("许嵩", 35);
        Student s3 = new Student("胡夏", 36);

        Student s4 = new Student("胡夏", 36);

        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        // 在Student类中不重写hashcode方法和equals方法 则成员变量相同的对象也会被存储进集合中
        // 在Student类中重写hashcode和equals方法,快捷键是 小键盘numlock ==》 alt + insert==》选择hashcode和equals==》接下来全是next
        for (Student st : hs){
            System.out.println(st.getName() + ", " + st.getAge());
        }
    }
}

HashSet集合

概述

  • HashSet集合存储在java.util包下,使用需要导包
  • 该类实现Set接口,低层由哈希表支持
  • 对集合的迭代顺序不做任何保证,也就是存储和迭代输出的顺序不一致
  • 没有带索引的方法,所以不能使用普通for循环遍历,但是可以使用迭代器iterator和增强for循环
  • 由于是Set集合,所以不能包含重复元素的集合

HashSet集合保证元素唯一性的源码分析

源码分析:

 HashSet<String> hs = new HashSet<String>();
 hs.add("hello");
 hs.add("java");
 hs.add("world");
 hs.add("world");

HashSet 跟进:
public boolean add(E e) { // e就是传入的字符串元素
   return map.put(e, PRESENT)==null;
   // 这里表示:
   // HashSet在底层是以键值对的形式存储,值存储在HashMap的key的位置,
   // HashMap值的位置存储的是persent,仅表示占位符。
}

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

public V put(K key, V value) { // key就是传入的元素,也就是add方法中的e
    return putVal(hash(key), key, value, false, true);
    // putVal方法的第一个元素:key调用hashCode方法的值
}

//hash值和hashCode方法有关
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        // Node[] 表示是一个数组,Node说明是一个节点 哈希表结构的一种实现,元素为节点Node的数组。

         // 如果哈希表没有被初始化,则对哈希表进行初始化
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
		//根据对象的哈希值计算对象的存储位置,如果该位置没有元素,就存储元素
        if ((p = tab[i = (n - 1) & hash]) == null)
        // 根据hash计算对象的在table中存储的索引值。hash & (length-1) 等价于 hash % length 
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            /*
            存入的哈希值和以前的哈希值进行比较 
            xhj理解:p.hash是以前的哈希值;hash是存入的哈希值
            	由于比较采用的&& 短路与,所以当前一个式子计算为false则后一个式子就不用计算了。
            	如果哈希值不同,会继续向下执行,把元素添加到集合(也就是else中的内容)
            	如果哈希值相同,会调用对象的equals()方法比较
            		如果返回false,会继续向下执行,把元素添加到集合
            		如果返回true,说明元素重复,不存储
*/
            if (p.hash == hash && 
                ((k = p.key) == key || (key != null && key.equals(k))))
                // 比较哈希值,是否相同,采用短路与,相同则比较key,key也相同,那么新创建的节点e = 原始节点p
                e = p;
            else if (p instanceof TreeNode)
            // 判断p 节点是不是树节点,也就是哈希表中数据存储结构是 红黑树 还是 链表
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

HashSet集合保证元素唯一性的源码具体执行过程:
1 调用对象的hashCode()方法获取对象的哈希值
2 根据对象的哈希值计算对象的存储位置
3 该位置是否有元素存储
没有——》将元素存储到该位置
有 ——》遍历该位置的所有元素,和新存入的元素比较哈希值是否相同

4 哈希值相同则调用equals()方法比较对象内容是否相同
相同 ——》 返回true,元素添加失败
不相同——》返回false,元素添加成功

HashSet集合要保证元素唯一性,需要重写hashCode和equals方法

扩展
^ 表示按位异或,相同为0,不同为1

LinkedHashSet集合

概述

  • LinkedHashSet集合存在与java.util包下,使用需要导包
  • 底层是由哈希表和链表实现的Set接口,具有可预测的迭代次序
  • 存储的顺序和取出的顺序是一致的,都是由链表保证的
  • 存储的元素是不能重复的,是由哈希表来保证的
  • LinkedHashSet继承自HashSet集合,实现Set集合

案例:证明有序性和唯一性

// 217 
public class LinkedHashSetDemo {
    public static void main(String[] args){
        LinkedHashSet<String> lhs = new LinkedHashSet<String>();

        lhs.add("hello");
        lhs.add("java");
        lhs.add("dream");

        lhs.add("dream");
        //添加重复元素,发现没有办法添加入集合中
        
        for(String s: lhs){
            System.out.println(s);
        }
        //输出内容是:hello java dream
    }
}

TreeSet集合

概述

  • TreeSet集合 在软件包java.util包中,使用需要导包;Class TreeSet< E > 泛型E表示TreeSet集合中的元素的类型
  • TreeSet集合没有直接实现Set接口,它实现了NavigableSet接口。
  • TreeSet集合依次实现哪些接口–》NavigableSet接口–》SortedSet接口–》Set接口,也就是说TreeSet间接实现Set接口
  • TreeSet集合中的元素是有序的,有序不是指存储和取出的顺序。
    由下述两种方式提供有序性:
    ①natrual ordering(自然排序接口),字母的顺序a-z;
    ②comparator(比较器接口)集合创建时提供,排序由哪种方式决定,取决于使用哪种构造方法。
方法名 说明
TreeSet() 无参构造方法,自然排序接口,构造一个新的、空的数组,根据其元素的自然排序进行排序
TreeSet(Comparator comparator) 有参构造方法,比较器接口,构造新的、空的数组,根据指定的比较器进行排序

TreeSet集合的有序性,是对集合元素进行排序。两种方式:

方法 说明
自然排序接口 TreeSet对象所属类需要实现Comparator接口,并重写compareTo(类名 对象名)方法
natrual ordering是一个接口 interface Comparable< T >,这个接口对实现它的每个类的对象强加一个整体排序,排序被称为自然排序接口
比较器排序 作为匿名内部传入TreeSet的构造方法,并重写compare方法(类名 对象名1,类名 对象名2)
Comparator接口,具有比较功能,实现对一些对象的集合施加整体排序,也被称为比较器接口
  • 没有带索引的方法,不能使用普通for循环遍历
  • 是Set集合,所以不包含重复元素

TreeSet类的clone方法

TresSet是可以被克隆的。

概述clone()方法
在java.util包中,使用的时候需要导包。
用于复制或克隆此TreeSet实例。
是非静态方法,只能使用类对象访问;
在克隆对象时不会引发异常。

public Object clone();
// 不接受任何参数。

案例

package itheima217.test6;

import java.util.TreeSet;

public class TreeSetClone {
    public static void main(String[] args) {
        TreeSet<String> tree_set = new TreeSet<String>();
        TreeSet<String> new_set = new TreeSet<String>();

        tree_set.add("C");
        tree_set.add("C++");
        tree_set.add("C#");
        tree_set.add("Java");

        System.out.println("TreeSet:" + tree_set);
        System.out.println("clone Set:" + new_set);

        new_set = (TreeSet) tree_set.clone();
        System.out.println("clone Set:" + new_set);
        // 输出结果:
        // TreeSet:[C, C#, C++, Java]
        //clone Set:[]
        //clone Set:[C, C#, C++, Java]
    }
}

TreeSet是基于红黑树实现的

  • TreeSet实际上是对TreeMap做了一层包装,TreeSet中有一个TreeMap。
  • TreeMap底层通过红黑树(Red-Black tree)实现。

红黑树

  • 是一种近似平衡的二叉查找树,它能够确保任一节点的左右子树的高度差不会超过二者中较低的那个的一倍。(左右子树的高度差 不会大于 最低子树的高度)(左右子树高度不存在倍数关系,也就是左子树高度 != a倍的右子树高度)
  • 红黑树是特殊的二叉查找树(binary search tree),需要满足以下条件:
    • 每个节点只有红色和黑色两种颜色;
    • 根节点必须是黑色的;
    • 红色节点不能连续(即红节点的孩子节点和父亲节点不能是红色);
    • 对于每个节点,从该点到null(树尾部)的任何路径,都含有相同个数的黑色节点。
案例:集合存储基本类型包装类

理解xhj:
集合对象存储元素,必须是引用数据类型。要想存储基本数据类型,比如int,就得使用基本类型包装类

// 217-TreeSetDemo
public class TreeSetDemo {
    public static void main(String[] args) {
        // 集合对象存储元素,必须是引用数据类型
        // 要想存储基本数据类型,比如int,就得使用基本类型包装类
        TreeSet<Integer> ts = new TreeSet<Integer>();

        //需要的是integer类型,这里填写10也是可以的,因为jdk5之后可以自动装箱
        ts.add(10);
        ts.add(40);
        ts.add(20);
        ts.add(0);
        ts.add(30);

        ts.add(30);
        //添加两个相同的元素,发现并没有添加进去,说明TreeSet集合不能存放重复元素

        for (Integer i : ts){
            System.out.println(i);
        }
        //输出顺序是:0 10 20 30 40

    }
}

自然排序Comparable使用

重点:

1TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序
	TresSet<T> treeset = new TreeSet<T>();
2 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T t)方法
	public class 类名 extends Comparable<T>{
		@Overridd
		public int compareTo(T t){}
		}
3 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

其中 this表示要添加的元素对象,s表示集合中存在的元素对象。
案例:集合元素学生对象,排序年龄从小到大,姓名字母顺序

需求
存储学生对象并遍历,创建TreeSet集合使用无参构造方法

要求
按照年龄从大到小排序,年龄相同时,按照姓名的字母顺序排序

理解分析:
分析Student类 中重写的Comparable接口的方法

compareTo方法中返回值:0 、正数、负数 具体的含义;

返回值 具体含义
负数 表示后续存储元素 比 之前元素的值 小
0 表示后续存储元素 和 之前元素的值 一样
正数 表示后续存储元素 比 之前元素的值 大

要实现升序排列 this.属性 - s.属性 解释:结果是正数(this》s),则this放在s之后;结果是负数(this《s),this放在结果之前。这样正好实现从小到大排序。

// 217-test1
// 第一点:
TreeSet存储元素所属的类必须继承Comparable接口
public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student() {
    }

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

    //由于是接口,所以需要重写里面的方法,重写的是compareTo方法
    @Override
    public int compareTo(Student s) {
        return 1;
    }
    第二点:return 0 的情况:认为后续存储元素和之前的元素一样,故不存储
    // wangzhaojun ,diaochan,yangyuhuan ,xishi 输入顺序
    // 修改成功后,原本存储四个元素,但是只存储了一个。wangzhaojun, 23
    // 原因:存储第一个元素之后,返回值是0,再存储第二个元素时,返回值还是0,程序会认为第二个元素和第一个元素同一个元素,就不存储了,后续的元素3、元素4一样

    第三点:return 1 (正数)的情况:认为后续存储元素比之前存储的元素大,所以添加在之后
    // wangzhaojun ,diaochan,yangyuhuan ,xishi 输入顺序
    // 四个元素全部存储在集合中,输出按输入的顺序输出
    // 输出顺序:wangzhaojun ,diaochan,yangyuhuan ,xishi
    // 解释:存储第一个元素,不需要和别的元素进行比较直接存储;存储第二个元素,和第一个元素比较后返回值是1,表示第二个比第一个大,所以存储在第一个元素之后

    第四点:return -1 (负数)的情况:认为后续存储的元素比之前存储的元素小,所以添加在之前
    // wangzhaojun ,diaochan,yangyuhuan ,xishi 输入顺序
    // 输出顺序:xishi,yangyuhuan,diaochan,wangzhaojun
}

测试:

// 217-test1
public class SudentDemo {
    public static void main(String[] args) {

        TreeSet<Student> ts = new TreeSet<Student>();

        Student s1 = new Student("wangzhaojun",23);
        Student s2 = new Student("diaochan",21);
        Student s3 = new Student("yangyuhuan", 25);
        Student s4 = new Student("xishi",24);

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

        for(Student s : ts){
            System.out.println(s.getName() + ", " + s.getAge());
        }
        // 第一点:
        //报错:Student cannot be cast to java.lang.Comparable
        // 原因是:comparable接口,该接口对每一个实现它的类强加一个整体排序,由于定义的Student类并没有实现该接口,所以会报错
    }
}

案例:

// 第一点:
// 217-test1
public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student() {
    }

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

    //由于是接口,所以需要重写里面的方法,重写的是compareTo方法
    @Override
    public int compareTo(Student s) {
        //年龄从小到大排序 (要求1)
        // 方法有this,使用this.成员变量 可以获取
        // this 表示要添加的元素,s表示已经存在的元素
        int num = this.age - s.age; // 此时按照age的升序排列 num 正数
        // num 正数,this.age 大于 s.age this存储在s之后
        // num 负数,this.age 小于 s.age this存储在s之前

//        int num = s.age - this.age; //按照age的降序排列
        // num 正数,this.age 小于 s.age  this存储在s之后 小数存储在大数之后
        // num 负数,this.age 大于 s.age  this存储在s之前 大数存储在小数之后
        // s2 添加的时候:this表示s2,s表示s1

        // 年龄相同时,按照姓名的字母顺序排序(要求2)
        int num2 = num==0 ? this.name.compareTo(s.name):num;
        // 字符串this.name 为什么可以直接调用compareTo
        // 因为字符串String实现了comparable接口,所以可以直接调用compareTo方法
        return num2;
    }
}

测试:
public class SudentDemo {
    public static void main(String[] args) {

        TreeSet<Student> ts = new TreeSet<Student>();

        Student s1 = new Student("wangzhaojun",23);
        Student s2 = new Student("diaochan",21);
        Student s3 = new Student("yangyuhuan", 25);
        Student s4 = new Student("xishi",24);

        Student s5 = new Student("wangsulong",24);
        Student s6 = new Student("wangsulong",24);

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

        //出现年龄相同,名字不相同情况,只比较年龄的comparaTo方法就得再加内容了
        // 由于 wangsulong 和 xishi 比较 w在x之前

        // 添加两个wangsulong 24  集合中只有一个

        for(Student s : ts){
            System.out.println(s.getName() + ", " + s.getAge());
        }
    }
}

比较器排序Comparator的使用

总结:

1TreeSet集合存储自定义对象,带参构造方法使用的是比较器排列对元素进行排序的
	TreeSet<T> treeset = new TreeSet<T>(Comparator comparator);
	参数是Comparator接口,实际上是需要传递Comparator接口的实现类对象
2 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1To2)方法
	TreeSet<T> treeset = new TreeSet<T>(new Comparator(){
			@Override
			public int compare(T t1,T t2){}
		//其中t1等同于compareTo方法中的this,t2等同于s
					});
3 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

返回值是1 表示t1放在t2之后;返回值是-1,表示t1放在t2之前。

理解xhj:

涉及到匿名内部类和匿名内部类中调用某类中的成员变量,采用 getXXX方法 而不是 对象.成员变量名
案例1:学生按照年龄排序。

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

// 217-test2
public class TreeSetDemo {
    public static void main(String[] args){

        // 创建TreeSet集合对象
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                // 参数传递两个的原因: 因为compare方法在测试类里面,所以它其中的this表示的是TreeSetDemo,而不是Student

                // 之前的this.age s.age
                // 匹配   s1        s2
                int num = s1.getAge() - s2.getAge();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });
        // 这个带参数的方法需要 传递的是comparator接口,实际上需要的是comparator接口实现类的对象
        // 一般方法:写一个类继承自Comparator接口的类,再创建对象
        // 本次采用匿名内部类的方式


        Student s1 = new Student("wangzhaojun",23);
        Student s2 = new Student("diaochan",21);
        Student s3 = new Student("yangyuhuan", 25);
        Student s4 = new Student("xishi",24);

        Student s5 = new Student("wangsulong",24);
        Student s6 = new Student("wangsulong",24);

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

        for(Student stu : ts){
            System.out.println(stu.getName() + ", " + stu.getAge());
        }
    }
}
案例2:成绩排序

需求:
用TreeSet集合存储多个学生信息(姓名、语文成绩、数学成绩),并遍历该集合

要求:
按照总分从高到低出现
主要条件是:总分从高到低,次要条件是总分相同按照语文成绩从高到低排序,语文成绩相同按照学生姓名排序

重点:
次要条件需要去分析。

// 217-test3
public class StudentDemo {
    public static void main(String[] args) {

        // 创建TreeSet集合对象
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
        // 通过比较器排序
                int sumS1 = s1.getMath() + s1.getChinese();
                int sumS2 = s2.getMath() + s2.getChinese();
                int num = sumS2 - sumS1;
                // 总分相同,按照语文成绩排序;
                int num2 = num == 0 ? s2.getChinese() -  s1.getChinese() : num;
                // 语文成绩相同,按照名字顺序排列
                int num3 = num2 == 0 ? s1.getName().compareTo(s2.getName()) : num2;
                return num3;
            }
        });

        Student s1 = new Student("wangsulong",45,12);
        Student s2 = new Student("xusong",100,100);
        Student s3 = new Student("weichen",42,100);

        // 问题1 当成绩总分相同的时候,按照语文成绩排序
        // 成绩相同的时候,学生就不会被添加进去了
        Student s4 = new Student("yuwenwen",43,99);

        // 问题2 当成绩总分相同的时候,语文成绩也相同
        // 总成绩相同,语文成绩也相同,比较学生姓名
        Student s5 = new Student("huachengyu",43,99);

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

        for(Student st : ts){
            System.out.println(st.getName() + ", " + st.getChinese()+", "+st.getMath()+", "+ (st.getChinese() + st.getMath()));
        }
    }
}
案例3:不重复的随机数

需求:
编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出

思路:
因为不能重复,所以使用Set集合;创建随机数,可以使用random。
Set集合创建对象,使用的是HashSet或TreeSet集合。

// 217 
public class SetDEmo {
    public static void main(String[] args) {

        //创建set集合
//        Set set = new HashSet();
        // HashSet集合 遍历是无序的
        Set<Integer> set = new TreeSet<Integer>();
        // 创建随机数对象
        Random r = new Random();

        // 循环判断set集合长度是否等于10
        while(set.size() < 10){
            int number = r.nextInt(20) + 1;
            set.add(number);
        }
        // 遍历:
        for(Integer i : set){
            System.out.println(i);
        }
    }
}

你可能感兴趣的:(java学习,java,开发语言,后端)