Day19 Java 泛型,增强for循环,Collection集合中Set接口的子类HashSet与TreeSet

30 篇文章 0 订阅

目录

泛型

泛型概述

泛型的优点:

泛型高级

泛型通配符

泛型的定义位置

泛型类

 泛型方法

 泛型接口

 增强For循环

增强for循环概述

 静态导入

 概述:

可变参数

List集合练习

集合的嵌套遍历

Set接口

Hashset

 LinkedHashSet

TreeSet   

自然排序                                                                                                                   

比较器排序


泛型

之前说过集合可以存放不同引用数据类型的数据,当集合中既含有String类型的数据,又含有其它类型的数据时,我们在遍历时会出现这样的问题:

代码引例:

import java.util.ArrayList;
import java.util.Iterator;

public class Test1 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("hello");
        list.add(20);
        list.add(12.48);
        list.add(new Students());
//        遍历
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            String s=(String)iterator.next();
            System.out.println(s);
        }
    }
}

该集合中存放了四种引用数据类型的数据,当在遍历集合,进行向下转型操作时会报错:

 ClassCastException:类型转换异常

这就是由于我们在集合中存放了不仅String类型的数据,还有Integer类型,Double类型和Student类型数据,但在强制类型转换时将遍历到的元素都转换成字符串类型,因此发生异常

解决办法:在存储数据时,将可以存储的数据类型限定为字符串类型,这样在强转时就不会报错

类似于在定义数组String[] arr=new String[3]时就已经将数组限定为只可以存放String类型的数据

Java提供了一种技术实现这种限定:泛型

泛型概述

把明确数据类型的工作,提前到了编译时期,在创建集合的时候明确存储元素的数据类型,有些类似于把数据当作参数一样传递,所以又称之为:参数化类型

泛型语句定义格式:<引用数据类型>        注意:尖括号中只能是引用数据类型

泛型的优点:

1、将我们运行时期出现的问题提前到了编译时期

2、不需要再做强制类型转换

3、优化了代码。消除了不必要的黄色警告线,使代码看起来更加整洁

通过观察API发现:泛型可以出现在类,接口,方法上,类似于<E>都叫泛型,一般情况泛型出现在大多使用的集合中

加入泛型后的代码:

import java.util.ArrayList;
import java.util.Iterator;

public class FanXinTest {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");

        Iterator<String> iterator = list.iterator();
//        遍历
        while(iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }
    }
}

泛型高级

泛型通配符<?>

任意类型,如果没有明确,那就是Object以及任意的Java类

? extends E  

向下限定,E及其子类

? super E

向上限定,E及其父类

代码举例:

在此之前创建三个类:Animal类,Cat类和Dog类,其中Cat类和Dog类继承自Animal类,类中不需要写具体代码。

import java.util.ArrayList;

public class GenericMyDemo {
    public static void main(String[] args) {
        ArrayList<Animal> animals1 = new ArrayList<>();
        ArrayList<Dog> dogs1 = new ArrayList<>();
        ArrayList<Cat> cats1 = new ArrayList<>();

//        任意调用,没有明确就是Object以及其他的Java类
        ArrayList<?> animals2 = new ArrayList<Animal>();
        ArrayList<?> dogs2 = new ArrayList<Dog>();
        ArrayList<?> cats2 = new ArrayList<Cat>();
        ArrayList<?> objects1=new ArrayList<Object>();
//        向下限定
        ArrayList<? extends Animal > animals3 =new ArrayList<Animal>();
        ArrayList<? extends Animal> cats3=new ArrayList<Cat>();
        ArrayList<? extends Animal> dogs3=new ArrayList<Dog>();
//        ArrayList<? extends Animal> objects2=new ArrayList<Object>();
//        向上限定
        ArrayList<? super Animal> cats4 =new ArrayList<Animal>();
        ArrayList<? super Animal> dogs4 =new ArrayList<Object>();

    }
}

泛型的定义位置

泛型类

就是把泛型定义在类上

定义格式:

public class 类名<泛型类型1,...>   

注意:这里的泛型类型可以不止一个,但是泛型类型必须是引用数据类型,这里<>中的内容仅仅表示的是一种参数数据类型,参数类型是一种变量,该变量要符合变量的命名规则,可以是任意符合标识符规则的名字

一般情况下在定义时习惯使用一个大写字母表示。

举例:

//这里是自定义一个泛型类
public class GenericDemo1<T> {
    private T obj;
    public T getObj(){
        return obj;
    }
    public void setObj(T obj){
        this.obj=obj;
    }
}

泛型类的测试类

//这里是泛型类的测试类
public class GenericDmeo1Test {
        public static void main(String[] args) {
            GenericDemo1<String> demo1 = new GenericDemo1<>();

            demo1.setObj("hello");
            String obj = demo1.getObj();
            System.out.println(obj);
        }
}

输出结果: 

 泛型方法

就是把泛型定义在方法上

定义格式:public <泛型类型> 返回类型 方法名(泛型类型 形参)

代码举例:

由于将来不知道需要传入什么类型的数据,因此定义泛型方法


public class Gdemo2 {
//      泛型方法
    public <R> void show(R r){
        System.out.println(r);
    }
}

泛型方法的测试类

public class Gtest2 {
    public static void main(String[] args) {
        Gdemo2 gdemo2 = new Gdemo2();
//        Stirng类型
        gdemo2.show("hello");
//        Integer类型
        gdemo2.show(19);
//        Double类型
        gdemo2.show(15.23);
    }
}

输出结果:

 泛型接口

就是把泛型定义在接口上

定义格式:public interface 接口名<泛型类型1,...>

代码举例:

public interface Gdemo3<W> {
    void show(W w);

}

该接口的实现类

public class Gdemo3Impl<W> implements Gdemo3<W>{
    @Override
    public void show(W w) {
        System.out.println(w);
    }
}

测试类

public class Gtest3{
    public static void main(String[] args) {
        Gdemo3Impl<String> gdemo3 = new Gdemo3Impl<String>();
        gdemo3.show("world");
//        gdemo3.show(20);已经限定为String类型,不可以使用其他类型

    }
}

输出结果:

 增强For循环

总结:

JDK1.5之后出现的新特性:泛型,增强for循环,包装类,Scanner,枚举

增强for循环概述

增强for循环就是简化数组和Collection集合的遍历

语句定义格式:

for(元素数据类型 变量名(自定义) : 数组或者Collection集合){

        使用变量即可,该变量就是元素

}

增强for循环的好处:简化遍历

代码举例:

使用增强for循环遍历数组:

public class ForTest {
    public static void main(String[] args) {
//        数组存储数据遍历
        int[] arr={11,232,34,55,6};
//       使用普通for循环遍历
        for(int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }
//        使用增强for循环遍历
        System.out.println("-------增强for循环遍历-------");
        for (int num : arr){
            System.out.println(num);
        }
    }
}

输出结果:

 使用增强for循环遍历集合:

import java.util.ArrayList;

public class ForTest2 {
    public static void main(String[] args) {
        //        集合存储对象遍历
        ArrayList<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");
        list.add("hbase");
//        使用普通for循环遍历
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
        System.out.println("-------增强for循环遍历-------");
//        使用增强for循环遍历
        for(String s : list){
            System.out.println(s);
        }
    }
}

如果该集合为null的话,直接使用增强for循环会报错:NullPointerException 空指针异常

所以我们应该在增强for循环之前加入一个判断:判断该集合是否为空即可

import java.util.ArrayList;

public class ForTest2 {
    public static void main(String[] args) {
        //        集合存储对象遍历
        ArrayList<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");
        list.add("hbase");
//        使用普通for循环遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("-------增强for循环遍历-------");
//        使用增强for循环遍历
        for (String s : list) {
            System.out.println(s);
        }
        list = null;//将集合赋值为空
        if (list!=null) {
            for (String s : list) {
                System.out.println(s);
            }
        }else{
            System.out.println("该集合为空");
        }
    }

}

输出结果:

增强for循环是代替迭代器的,如何验证?

迭代器会出现并发修改异常,若增强for循环也会出现并发修改异常,则说明增强for循环是代替迭代器的。

代码同迭代器中代码类似:

代码实现:在增强for循环中加入equals,若相同,则添加元素hadoop到集合中

for (String s : list) {
            if("hello".equals(s)){
                list.add("hadoop");
            }
        }

输出结果:ConcurrentModificationException 并发修改异常

 说明增强for循环其实就是替代迭代器的

解决办法:迭代器遍历,迭代器修改;集合遍历,集合修改

 这里只给出前一种解决办法:

 ListIterator<String> iterator = strings.listIterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            if("java".equals(next)){
                iterator.add("spark");
            }
        }
        System.out.println(strings);

输出结果:

 静态导入

 概述:

格式:import static 包名...类名.方法名;

可以直接导入到方法级别

注意事项:方法必须是静态的

举例:

在调用Math类中的一些方法时我们需要重复的使用Math.方法名();从其它类中调用方法也是如此,这时只需要使用静态导入即可解决。

注意:当本类中的方法与静态导入的方法名冲突时,调用的是本类中的方法

代码如下:

其他类定义:

public class QitaClass {
    public static void show(String s){
        System.out.println(s);
    }
    public static void fun(){
        System.out.println("这世界很美好!!!");
    }
}

测试类:

import static java.lang.Math.abs;
import static java.lang.Math.pow;
import static test.Test.src.com.QitaClass.fun;
import static test.Test.src.com.QitaClass.show;

public class DaoTest {
    public static void main(String[] args) {
//        Math类中的方法
        System.out.println(Math.abs(-100));
        System.out.println(Math.pow(2, 3));
//        使用静态导入改进:导入Math类中需要调用的方法:
//        import static java.lang.Math.abs;
//        import static java.lang.Math.pow;
        System.out.println(abs(-23));
        System.out.println(pow(2, 4));
        fun();//此时调用的时本类中的fun()方法
        show("你好世界");
//        若仍然想调用其他类中的fun方法,解决办法为:加上前缀调用
        test.Test.src.com.QitaClass.fun();
    }
    public static void fun(){
        System.out.println("本类中的fun()方法:this world is very good !!!");
    }
}

 输出结果:

可变参数

格式:

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

注意:这里的变量其实是一个数组,如果一个方法有可变参数,并且有多个参数,可变参数一定是最后一个参数。

即若使用可变参数定义方法时,有其他数据类型参与的时候,将可变参数的定义放在最后。

Arrays工具类中的一个方法:public static <T> List<T> asList(T... a)

该方法其实就是将数组转变为一个集合

代码举例:

import java.util.Arrays;
import java.util.List;

public class ChangeDemo {
    public static void main(String[] args) {
        int a=1;
        int b=2;
        int c=4;
        sum(a,b);
        sum(a,b,c);
        sum("赵云",45,20,30);

//        Arrays工具类中的一个方法
         List<String> list = Arrays.asList("这是", "数组", "转变", "集合");
        for(String s : list){
            System.out.println(s);
        }
    }
//    public static void sum(int a,int b){//求两个数的和
//        System.out.println(a+b);
//    }
//    public static void sum(int a,int b,int c){//求三个数的和
//        System.out.println(a+b+c);
//    }
//    使用可变参数改进:含有多个参数,将可变参数放在最后
    public static void sum(String s,int... ints){
        int sum=0;
        for (int i : ints){
            sum+=i;
        }
        System.out.println(s+"的成绩总分为:"+sum);
    }
//    使用可变参数改进求几个数的和
    public static void sum(int... ints){
        int sum=0;
        for(int i : ints){
            sum+=i;
        }
        System.out.println(ints.length+"个数的和为:"+sum);
    }
}

输出结果:

注意:同一个方法定义中,可变参数只能出现一次:即不会出现如下代码行:

public static void sum(int... ints,int... ints2){}

List集合练习

集合的嵌套遍历

目前学校有五年级学生和六年级学生。每个年纪有很多的学生,每个学生都是一个对象,可以使用集合表示一个班级的学生

五年级学生:ArrayList<Student> classList5;

六年级学生:ArrayList<Student> classList6;

无论是几年级的学生都属于学校的年级,于是学校本身也可以通过集合表示:

ArrayList<ArrayList<Student>> school

像这种现象就叫做集合嵌套

 代码举例:

学生类:

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

集合嵌套类:

import java.util.ArrayList;
import java.util.Iterator;

public class SchoolDemo {
    public static void main(String[] args) {
//        创建学校对象
        ArrayList<ArrayList<Student>> school = new ArrayList<>();
//        创建年纪对象
        ArrayList<Student> classList5 = new ArrayList<Student>();
        ArrayList<Student> classList6 = new ArrayList<>();

//        添加数据到集合
        school.add(classList5);
        school.add(classList6);

        Student s1 = new Student("诸葛孔明", 15);
        Student s2 = new Student("司马仲达", 12);
        Student s3 = new Student("周公瑾", 16);
        Student s4 = new Student("陈宫", 15);
        classList5.add(s1);
        classList5.add(s2);
        classList5.add(s3);
        classList5.add(s4);

        Student s5 = new Student("刘被", 23);
        Student s6 = new Student("曹操", 24);
        Student s7 = new Student("孙佺", 23);

        classList6.add(s5);
        classList6.add(s6);
        classList6.add(s7);

//        增强for循环嵌套遍历
        for(ArrayList<Student> sc : school){
            for(Student student : sc){
                System.out.println(student);
            }
        }
        System.out.println("-----------------------普通for循环遍历---------------------");
        for (int i=0;i< school.size();i++){
            if (i==0){
                System.out.println("===========五年级学生==============");
                for (int j =0;j<school.get(i).size();j++){
                    System.out.println(school.get(i).get(j));
                }
            }
            else if(i==1){
                System.out.println("===========六年级学生==============");
                for(int j=0;j<school.get(i).size();j++){
                    System.out.println(school.get(i).get(j));
                }
            }
        }
        System.out.println("----------------------迭代器遍历--------------------------");
        Iterator<ArrayList<Student>> iterator = school.iterator();
        while(iterator.hasNext()){
            ArrayList<Student> sc = iterator.next();
            Iterator<Student> iterator1 = sc.iterator();
            while(iterator1.hasNext()){
                Student student = iterator1.next();
                System.out.println(student);
            }
        }
    }
}

输出结果:增强for循环遍历和迭代器遍历结果相同:

 普通for循环遍历结果:

 获取十个不重复的1到20以内的随机数:

import java.util.ArrayList;
import java.util.Random;

public class RanTest {
    public static void main(String[] args) {
        Random random = new Random();

        ArrayList<Integer> list = new ArrayList<>();

        int count=0;
        while(count<10){
            int i = random.nextInt(20)+1;
            if(!list.contains(i)){
                list.add(i);
                count++;
            }
        }
        System.out.println(list);
    }
}

输出结果(每次都会不同):

 键盘录入多个数据,以0结束,在控制台输出这些数据中的最大值

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class MaxDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        ArrayList<Integer> list = new ArrayList<>();
        boolean flag=true;
        System.out.println("请录入数据:");
        while(flag){
            int num = sc.nextInt();
            if(num==0){
                flag=false;
                System.out.println("数据录入完成!");
            }else{
                list.add(num);
            }
        }
        Object[] obj = list.toArray();
        Arrays.sort(obj);
        System.out.println("最大值为:"+obj[obj.length-1]);
    }
}

输出结果:

Set接口

一个不包含重复元素的Collection

Set集合是唯一的,并且元素的顺序是无序的集合

Hashset

底层结构是哈希表(元素是链表的数组)

哈希表依赖于哈希值存储

代码举例:使用Set集合存储字符串并遍历

import java.util.HashSet;
import java.util.Set;

public class Test1 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("hello");
        set.add("world");
        set.add("hello");
        set.add("bigdata");
        set.add("hive");
        set.add("java");
        set.add("bigdata");

        for(String set2 : set){
            System.out.println(set2);
        }
    }
}

输出结果:

 存储自定义对象并遍历

import java.util.HashSet;
import java.util.Set;

public class Test2 {
    public static void main(String[] args) {
        Set<Student> set = new HashSet<Student>();
        Student s1 = new Student("小赵", 18);
        Student s2 = new Student("小钱", 17);
        Student s3 = new Student("小孙", 19);
        Student s4 = new Student("小李", 17);
        Student s5 = new Student("小赵", 18);

        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        for (Student students : set) {
            System.out.println(students);
        }
    }
}

输出结果:这里应该不包含重复元素,但是结果包含了重复元素:

造成这样的原因需要去源码中查看add方法的实现源码:

经过查看源码发现该HashSet中的add方法与HashCode和equals方法有关,而Student类中没有重写HashCode和equals方法,因此调用的是Object类中的HashCode和equals方法,故比较的是地址值,对于不同的对象含有不同的地址值,因此无法去重。

解决办法:重写HashCode方法和equals方法即可

 @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

 输出结果:

 LinkedHashSet

1、底层数据结构是哈希表和链表

2、哈希表保证元素唯一

3、链表保证了元素的有序(存储和取出的顺序一致)

4、线程不安全,效率高

public class HashSet<E> implements Set<E>

public class LinkedHashSet<E> extends HashSet<E> implements Set<E>

代码举例:

import java.util.LinkedHashSet;

public class Test3 {
    public static void main(String[] args) {
        LinkedHashSet<String> hashSet = new LinkedHashSet<>();
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("java");
        hashSet.add("bigdata");
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("hadoop");
        hashSet.add("bigdata");

//        遍历
        for (String strings : hashSet){
            System.out.println(strings);
        }
    }
}

输出结果:

TreeSet   

底层数据结构是红黑树

元素唯一,元素可按照某种规则进行排序

两种排序方式:自然排序 ;比较器排序

代码举例:

Treeset存储Integer类型的数据并遍历:

import java.util.TreeSet;

public class Ttest1 {
    public static void main(String[] args) {
        TreeSet<Integer> treeSet = new TreeSet<>();
        treeSet.add(23);
        treeSet.add(24);
        treeSet.add(14);
        treeSet.add(56);
        treeSet.add(23);
        treeSet.add(70);
        treeSet.add(16);
        treeSet.add(14);
//        遍历
        for (Integer integer : treeSet){
            System.out.println(integer);
        }
    }
}

 输出结果:

    

自然排序                                                                                                                   

TreeSet存储学生对象并遍历:         

 按照正常的写法,当我们运行的时候,会报错: java.lang.ClassCastException 类转换异常

这是由于在创建TreeSet对象时使用的是无参构造方法,进行的是自然排序,而在这里的底层源码中有向下转型代码:Comparable<? super K> k = (Comparable<? super K>) key;

但是Student类中没有实现Comparable接口重写compareTo()方法,无法向下转型

解决办法:在Student类中实现Comparable接口即可

Student1类:

import java.util.Objects;

public class Student1 implements Comparable<Student1> {
    private String name;
    private int age;

    public Student1() {
    }

    public Student1(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(Student1 o) {
//        这里的返回值具体返回什么应该由我们自己来定义
        int i = this.age - o.age;
        int i2 = i == 0 ? this.name.compareTo(o.name) : i;
        return i2;
    }
}

测试类:

import java.util.TreeSet;

public class Ttest2 {
    public static void main(String[] args) {
        TreeSet<Student1> students = new TreeSet<Student1>();
        Student1 s1 = new Student1("云", 19);
        Student1 s2 = new Student1("赵云", 18);
        Student1 s3 = new Student1("赵子龙", 20);
        Student1 s4 = new Student1("常山赵子龙", 21);
        Student1 s5 = new Student1("赵子龙", 20);

        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        for (Student1 s : students){
            System.out.println(s);
        }
    }
}

输出结果:这里会发现是按照年龄的大小来进行排序的

需求:使用TreeSet存储学生对象并以姓名的长度来排序

学生类:

import java.util.Objects;

public class Student3 implements Comparable<Student3> {
    private String name;
    private int age;

    public Student3() {
    }

    public Student3(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 int compareTo(Student3 o) {
//        比较姓名的长度是否相等
        int i = this.name.length() - o.name.length();
//        若相等,比较姓名的内容是否相同
        int i2 = i == 0 ? this.name.compareTo(o.name) : i;
//        若相同,比较年龄是否相等
        int i3 = i2 == 0 ? this.age - o.age : i2;
        return i3;
    }

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


}

测试类:

import java.util.TreeSet;

public class Ttest3 {
    public static void main(String[] args) {
        TreeSet<Student3> students3 = new TreeSet<>();
        Student3 s1 = new Student3("yun", 19);
        Student3 s2 = new Student3("zhaoyun", 18);
        Student3 s3 = new Student3("zhaozilon", 20);
        Student3 s4 = new Student3("changshanzhaozilon", 21);
        Student3 s5 = new Student3("yun", 22);
        students3.add(s1);
        students3.add(s2);
        students3.add(s3);
        students3.add(s4);
        students3.add(s5);

        for(Student3 sc : students3){
            System.out.println(sc);
        }
    }
}

输出结果:

比较器排序

利用TreeSet创建对象时的带参数的构造方法来进行比较器排序

TreeSet(Comparator<? super E> comparator)

构造一个新的,空的数集,根据指定的比较器进行排序

这里需要实现Comparator接口,重写compare()方法

代码举例:

实现Comparator接口的实现类ComparatorImpl:

import java.util.Comparator;

public class ComparatorImpl implements Comparator<Student4> {

    @Override
    public int compare(Student4 o1, Student4 o2) {
//        比较姓名的长度
        int i = o1.getName().length() - o2.getName().length();
//        比较姓名的内容
        int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
//        比较年龄的大小
        int i3 = i2 == 0 ? o1.getAge() - o2.getAge() : i2;
        return i3;
    }
}

这里是具体的测试类 

import java.util.TreeSet;

public class Ttest4 {
    public static void main(String[] args) {
        ComparatorImpl comparator = new ComparatorImpl();
        TreeSet<Student4> student4s = new TreeSet<>(comparator);//使用带参构造
//        创建学生对象
        Student4 s1 = new Student4("yun", 19);
        Student4 s2 = new Student4("zhaoyun", 18);
        Student4 s3 = new Student4("zhaozilon", 21);
        Student4 s4 = new Student4("chanshangzhaozilon", 20);
        Student4 s5 = new Student4("chanshangzhaoyun", 20);
        Student4 s6 = new Student4("zhaoyun", 22);
        Student4 s7 = new Student4("yun", 19);

//        添加到集合
        student4s.add(s1);
        student4s.add(s2);
        student4s.add(s3);
        student4s.add(s4);
        student4s.add(s5);
        student4s.add(s6);
        student4s.add(s7);

//        遍历
        for(Student4 student4 : student4s){
            System.out.println(student4);
        }

    }
}

 输出结果:

总结:

自然排序使用无参构造创建对象,需要在元素类中实现Comparable接口,重写compareTo()方法

比较器排序使用带参构造创建对象,需要在元素类中实现Comparator接口,重写Compare()方法

比较器排序这里还可以使用匿名内部类进行comparator接口的实现:

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

public class Ttest4 {
    public static void main(String[] args) {
//        ComparatorImpl comparator = new ComparatorImpl();
//        TreeSet<Student4> student4s = new TreeSet<>(comparator);
//        使用匿名内部类改进:
        TreeSet<Student4> student4s = new TreeSet<>(new Comparator<Student4>() {
            @Override
            public int compare(Student4 o1, Student4 o2) {
//                比较姓名的长度
                int i = o1.getName().length() - o2.getName().length();
//                比较姓名的内容
                int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
//                比较年龄的大小
                int i3 = i2 == 0 ? o1.getAge() - o2.getAge() : i2;
                return i3;
            }
        });
        Student4 s1 = new Student4("yun", 19);
        Student4 s2 = new Student4("zhaoyun", 18);
        Student4 s3 = new Student4("zhaozilon", 21);
        Student4 s4 = new Student4("chanshangzhaozilon", 20);
        Student4 s5 = new Student4("chanshangzhaoyun", 20);
        Student4 s6 = new Student4("zhaoyun", 22);
        Student4 s7 = new Student4("yun", 19);

        student4s.add(s1);
        student4s.add(s2);
        student4s.add(s3);
        student4s.add(s4);
        student4s.add(s5);
        student4s.add(s6);
        student4s.add(s7);

        for(Student4 student4 : student4s){
            System.out.println(student4);
        }

    }
}

 输出结果不变

通过查看逻辑来看,这两种排序实现的其实就是按照树的中序遍历方式进行排序的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值