第十九天集合(下)

泛型通配符

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

? extends E

向下限定,E及其子类

? super E

向上限定,E及其父类

父类Animal

public class Animal {
}

子类Dog

public class Dog extends Animal {
}

子类Cat

public class Cat extends Animal {
}
import java.util.ArrayList;

public class GenericDemo1 {
    public static void main(String[] args) {
        ArrayList<Animal> list1 = new ArrayList<Animal>();
        ArrayList<Dog> list2 = new ArrayList<Dog>();
        ArrayList<Cat> list3 = new ArrayList<Cat>();
        //泛型通配符<?>
        //任意类型,如果没有明确,那么就是Object以及任意的Java类了
        ArrayList<?> list = new ArrayList<Animal>();
        ArrayList<?> list4 = new ArrayList<Dog>();
        ArrayList<?> list5= new ArrayList<Cat>();
        //? super E  向上限定,E及其父类
        ArrayList<?super Animal> list6 = new ArrayList<Animal>();
        ArrayList<? super Animal> list7 = new ArrayList<Object>();
//        ArrayList<? super Animal> list11 = new ArrayList<Dog>();会报错



        //? extends E  向下限定,E及其子类
        ArrayList<? extends Animal> list8 = new ArrayList<Animal>();
        ArrayList<? extends Animal> list9 = new ArrayList<Dog>();
        ArrayList<? extends Animal> list10 = new ArrayList<Cat>();
//        ArrayList<? extends Animal> list11 = new ArrayList<Object>();会报错

    }
}

泛型类

把泛型定义在类上

格式:public class 类名<泛型类型1,…> 注意:泛型类型必须是引用类型 这里的<>里面的内容仅仅表示的使一种参数数据类型,参数类型是一种变量 既然是一种变量,就要符合变量的命名规则,可以使任意符合标识符起名字规则的名字。 一般情况下,在定义的时候,习惯用一个大写字母表示。

public class GenericTool1 <T>{
    private T obj;
    public T getObj(){
        return obj;
    }
    public void setObj(T obj){
        this.obj=obj;
    }
}

测试类:

public class GenericTest1 {
    public static void main(String[] args) {
        //如果不加泛型,默认使Object类型
//        GenericTool1 gt1=new GenericTool1();
//        gt1.setObj("hello");
//        gt1.setObj("20");
//        gt1.setObj("3.1415");
        GenericTool1<String> gt2 = new GenericTool1<>();
        gt2.setObj("hell0");
//        gt2.setObj(20);会报错
        String obj=gt2.getObj();
    }
}

泛型方法

把泛型定义在方法上

格式:public 返回类型 方法名(泛型类型 .)

public class GenericTool2 {
//    public void show(String s) {
//        System.out.println(s);
//    }
//
//    public void show(int i) {
//        System.out.println(i);
//
//    }
//
//    public void show(double j) {
//        System.out.println(j);
//    }
    //用泛型方法改进,因为将来不确定要传入什么类型的数据
    public <F>void show(F f){
        System.out.println(f);
    } 
}

测试类:

public class GenericTest2 {
    public static void main(String[] args){
        GenericTool2 genericTool2 = new GenericTool2();
        genericTool2.show("herllo");
        genericTool2.show(10);
        genericTool2.show(3.1415);
    }
}

泛型接口

把泛型定义在接口上

格式:public interface 接口名

接口类

public interface GenericTool3<W> {
    public abstract void show(W w);
}
public class Genericlmpl<W> implements GenericTool3<W> {

    @Override
    public void show(W w) {
        System.out.println(w);
    }
}
public class GenericTest3 {
    public static void main(String[] args) {
        Genericlmpl<String> stringGenericlmpl = new Genericlmpl<>();
        stringGenericlmpl.show("hello");
//        stringGenericlmpl.show(20);会报错
    }
}
结果:
hello

JDK1.5之后出现的新特性:

到目前为止,学过哪些知识使JDK1.5之后出现的?

泛型,增强for,包装类,Scanner,枚举

增强for循环概述:简化数组和Collection集合的遍历

语句定义格式:

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

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

}

好处:简化遍历

import java.util.ArrayList;
import java.util.ListIterator;

public class ForDemo {
    public static void main(String[] args) {
     int[] arr = {1,2,3,4,5,6};
     for (int i=0;i< arr.length;i++){
         System.out.println(arr[i]);
     }
        System.out.println("使用增强for循环遍历数组");
     for (int num:arr){
         System.out.println(num);
     }
        System.out.println("================================");
        ArrayList<String> strings = new ArrayList<>();
        strings.add("hello");
        strings.add("world");
        strings.add("java");
        strings.add("bigdata");
        strings.add("hadoop");
        for (String string :strings){
            System.out.println(string);
        }
        //我们应该在遍历之前判断一下是不是null
        if (strings!=null){
            for (String string :strings){
                System.out.println(string);
            }
        }else {
            System.out.println("该集合为空");
        }
        //其实增强for循环就是用来替代迭代器的
        //怎么去验证它就是用来替代迭代器的呢?
        //使用并发修改异常去验证
//        for (String s:strings){
//            //ConcurrentModificationException
//            if ("java".equals(s)){
//                strings.add("spark");
//            }
//        }
        ListIterator<String> stringListIterator = strings.listIterator();
        while (stringListIterator.hasNext()){
            String next = stringListIterator.next();
            if ("java".equals(next)){
                stringListIterator.add("spark");
            }
        }
        System.out.println(strings);


    }
}

静态导入:

语句定义格式:import static 包名...类名.方法名;

可以直接导入到方法级别

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

public class StaticClass {
    public static void fun() {
        System.out.println(" 数家科技");
    }
    public static void show(String s){
        System.out.println(s);
    }
}
import static Days19.StaticClass.fun;
import static Days19.StaticClass.show;
import static java.lang.Math.abs;
import static java.lang.Math.pow;

public class StaticImportDemo {
    public static void main(String[] args) {
//        System.out.println(abs(-100));
//        System.out.println(Math.pow(2,3));
//        System.out.println(Math.max(1100,200));
        //有没有什么方法,不同写类名,直接写方法名?
//        System.out.println(abs(-200));
        //这时候,就需要静态导入的技术
        System.out.println(abs(-200));
        System.out.println(pow(2, 4));
        fun();
        //当静态导入的方法名与本类中的方法名冲突的时候,调用的是本类中的方法
        show("spark");

        //如果此时我就是想使用静态导入的方法,怎么办?就是还想调用StaticClass种的方法
//将前缀路径写完整
        Days19.StaticClass.show("flink");

    }

    public static void show(String s) {
        System.out.println("这是本类中的show方法");
    }
}

结果:

200
16.0
 数家科技
这是本类中的show方法
flink

可变参数概述

定义方法的时候不知道该定义多少个参数

格式

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

注意:

这里的变量其实是一个数组

如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个

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

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class ArgsDemo {
    public static void main(String[] args) {
        //使用方法求两个数之和
        int a = 10;
        int b = 20;
        sum(a, b);
        //使用方法求三个数之和
        int a1 = 10;
        int b1 = 20;
        int c2 = 30;
        sum(a, b, c2);
        sum("小明", 20, 56, 78, 90);
        //数组--->List(ArrayList)集合
        List<String> strings = Arrays.asList("hello", "world", "java", "bigdata");

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

    //    public static void sum(int a,int b){
//        System.out.println("两个数之和为:"+(a+b));
//    }
//    public static void sum(int a1,int b1,int c1){
//        System.out.println("三个数之和为:"+(a1+b1+c1));
//    }
//使用可变参数的形式定义加法的方法
//注意可变参数的变量最终是一个数组的变量名
//这里将来传入多个参数的时候,内部会自动将这多个参数形成一个数组,数组名就是我们定义的ints
    public static void sum(int... ints) {
        int sum = 0;
        for (int i : ints) {
            sum += i;
        }
        System.out.println(sum);
    }

    //当使用可变参数定义方法时候,有其他数据类型参与的时候,将可变参数的定义放在最后
    public static void sum(String s, int... ints) {
        int sum = 0;
        for (int i : ints) {
            sum += i;
        }
        System.out.println(sum);
    }

    //同一个方法定义中,可变参数只能出现一次
//    public static void sum(int... ints1,int... ints2){
//
//    }会提示错误
    

}

集合的嵌套遍历

需求:目前,数加学院有十五期,十六期。每一期有很多学生,每个学生都是一个学生对象

可以用一个集合表示一个班的学生

十五期的学生:ArrayList classList15;

十六期的学生:ArrayList classList16;

无论是十五也好还是十六期,都是属于数加学院的班级

数加学院本身也可以通过集合表示:ArrayList> shujia;

这样的现象叫做集合嵌套

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 ListQianTaoTest {
    public static void main(String[] args) {
        //定义一个十五期的班级集合
        ArrayList<Student> ClassList15 = new ArrayList<>();
        //定义一个十六期的班级集合
        ArrayList<Student> ClassList16 = new ArrayList<>();
        //定义一个学院集合
        ArrayList<ArrayList<Student>> xueyuan = new ArrayList<>();
        //将15,16,期加入到集合中
        xueyuan.add(ClassList15);
        xueyuan.add(ClassList16);
        //创建15期对象
        Student s1 = new Student("小名", 21);
        Student s2 = new Student("小白", 22);
        Student s3 = new Student("小黄", 26);
        Student s4 = new Student("小黑", 20);
        //创建16期对象
        Student s5 = new Student("小蓝", 19);
        Student s6 = new Student("小红", 21);
        Student s7 = new Student("小紫", 22);
        Student s8 = new Student("小光", 28);
        //将15期的学生对象添加到十五集合中
        ClassList15.add(s1);
        ClassList15.add(s2);
        ClassList15.add(s3);
        ClassList15.add(s4);

        //将16期的学生对象添加到十六集合中
        ClassList16.add(s5);
        ClassList16.add(s6);
        ClassList16.add(s7);
        ClassList16.add(s8);
        //遍历
        //增强for循环遍历
        for (ArrayList<Student> a : xueyuan) {
            System.out.println(xueyuan);
            for (Student S : a) {
                System.out.println(S);
            }
        }
        for (int i = 0; i < xueyuan.size(); i++) {
            if (i == 0) {
                System.out.println("=============十五期:===================");
                for (int j = 0; j < xueyuan.get(i).size(); j++) {
                    Student student = xueyuan.get(i).get(j);
                    System.out.println(student);
                }
            } else if (i == 1)  {
                System.out.println("=============十六期:===================");
                for (int j = 0; j < xueyuan.get(i).size(); j++) {
                    Student student = xueyuan.get(i).get(j);
                    System.out.println(student);
                }
            }
        }
        System.out.println("========================================================");

        //迭代器遍历
        Iterator<ArrayList<Student>> iterator = xueyuan.iterator();
        while (iterator.hasNext()){
            ArrayList<Student> next = iterator.next();
            Iterator<Student> iterator1 = next.iterator();
            while (iterator1.hasNext()){
                Student next1 = iterator1.next();
                System.out.println(next1);
            }
        }
    }
}
结果:
[[Student{name='小名', age=21}, Student{name='小白', age=22}, Student{name='小黄', age=26}, Student{name='小黑', age=20}], [Student{name='小蓝', age=19}, Student{name='小红', age=21}, Student{name='小紫', age=22}, Student{name='小光', age=28}]]
Student{name='小名', age=21}
Student{name='小白', age=22}
Student{name='小黄', age=26}
Student{name='小黑', age=20}
[[Student{name='小名', age=21}, Student{name='小白', age=22}, Student{name='小黄', age=26}, Student{name='小黑', age=20}], [Student{name='小蓝', age=19}, Student{name='小红', age=21}, Student{name='小紫', age=22}, Student{name='小光', age=28}]]
Student{name='小蓝', age=19}
Student{name='小红', age=21}
Student{name='小紫', age=22}
Student{name='小光', age=28}
=============十五期:===================
Student{name='小名', age=21}
Student{name='小白', age=22}
Student{name='小黄', age=26}
Student{name='小黑', age=20}
=============十六期:===================
Student{name='小蓝', age=19}
Student{name='小红', age=21}
Student{name='小紫', age=22}
Student{name='小光', age=28}
========================================================
Student{name='小名', age=21}
Student{name='小白', age=22}
Student{name='小黄', age=26}
Student{name='小黑', age=20}
Student{name='小蓝', age=19}
Student{name='小红', age=21}
Student{name='小紫', age=22}
Student{name='小光', age=28}

获取10个1-20之间的随机数,要求不能重复

1、由于我们不确定获取随机数的次数,长度不好确定,所以我们选择集合

2、随机数生成的方式:Random类:nextInt(int num): 左闭右开

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

public class RandomTest {
    public static void main(String[] args) {
        //创建随机数对象
        Random random = new Random();
        //创建集合储存随机数
        ArrayList<Integer> integers = new ArrayList<>();
        //定义一个变量统计集合里是否有十个元素
        int count=0;
        while (count<10){
            int i = random.nextInt(20)+1;
            if (!integers.contains(i)){
                integers.add(i);
                count++;
            }
        }
        System.out.println(integers);
    }
}
结果(随机):
[16, 2, 6, 11, 1, 14, 7, 4, 15, 19]

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

1、由于不知道输入多少次,所以用while循环进行输入

2、用集合存储数据

3、toArray()

4、Arrays.sort()

5、取最后一个元素就是最大值

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

public class ListTest {
    public static void main(String[] args) {
        //创建盘录入对像
        Scanner scanner = new Scanner(System.in);
        //创建集合对象
        ArrayList<Integer> integers = new ArrayList<>();
        boolean flag=true;
        while (flag){
            int i = scanner.nextInt();
            if (i==0){
                System.out.println("数据录入完毕");
                flag=false;
            }else {
                integers.add(i);
            }
        }
        Object[] objects = integers.toArray();
        Arrays.sort(objects);
        System.out.println("最大值为"+objects[objects.length-1]);
    }
}

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

在Set集合中存储的元素为什么不会有重复的呢?

import java.util.HashSet;

public class SetDemo {
    public static void main(String[] args) {
        HashSet<String> set1 = new HashSet<>();
        set1.add("hello");
        set1.add("world");
        set1.add("java");
        set1.add("bigdata");
        set1.add("hadoop");
        set1.add("world");
        set1.add("java");
        set1.add("hello");
        set1.add("spark");
        set1.add("spark");
        set1.add("hbase");
        set1.add("flink");
        set1.add("java");
        set1.add("hello");
        //遍历
        for (String s:set1){
            System.out.println(s);
        }
    }

}
结果:
flink
world
java
bigdata
spark
hello
hadoop
hbase

分析源码:

public interface Set extends Collection{
    void add(E e);
}

class HashSet implements Set{
    private transient HashMap<E,Object> map;

    private static final Object PRESENT = new Object();

    public HashSet() {
            map = new HashMap<>();
    }

    public boolean add(E e) {
            //E -- String
            //e -- "hello"
            return map.put(e, PRESENT)==null;
    }
}

class HashMap{
    //key -- "hello"
    //value -- new Object()
    public V put(K key, V value) {
            //读到这里我们知道put方法一定是与元素类中的hashCode()方法有关
            return putVal(hash(key), key, value, false, true);
    }

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


    // hash -- (h = key.hashCode()) ^ (h >>> 16)结合hashCode()计算出来的值
    // key -- "hello"
    // value -- new Object()
    // onlyIfAbsent -- false
    // evict -- true
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        //理解为哈希表存储的是一个一个的节点数组
        Node<K,V>[] tab;
        Node<K,V> p;
        int n, i;

        //判断哈希表是否初始化完毕,如果没有初始化,就在这一步初始化
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;

        //根据元素的对象计算好的哈希值再进行一次计算,计算出的是该元素存储在哈希表中的位置
        //如果该元素的位置是null,说明这个位置没有元素,可以进行存储,创建新的节点,存储元素
        //分析到这一步,我们再次验证一个结论,元素存储的位置与元素类中hashCode()有关
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            //如果该元素的位置不是null,说明这个位置上已经有元素了,可以确定的是哈希值是一样的
            //但是呢,我不能确定这两个元素就是同一个元素。
            Node<K,V> e;
            K k;

            //先将存入元素的哈希值与该位置上的元素的哈希值进行比较
            //如果哈希值都不一样,继续走判断instanceof
            //如果哈希值都一样,会调用元素的equals(k)方法进行比较
            //如果equals(k)方法比较的结果是false的话,继续向下执行最终会将元素添加到集合中或者不添加
            //如果equals(k)方法比较的结果是true的话,表示哈希值和内容都一样,表示元素重复了
            //就覆盖,从现象上来看,其实就是不赋值
            //说到这里,我们就已经知道HashSet中add()方法实际上与hashCode()方法和equals()方法有关
            //集合中会不会去重取决于元素类有没有重写hashCode()方法和equals()方法
            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                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;
    }

Student2类要重写equals方法

import java.util.Objects;

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

    public Student2() {
    }

    public Student2(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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student2 student2 = (Student2) o;
        return age == student2.age && Objects.equals(name, student2.name);
    }

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

测试类

import java.util.HashSet;

public class SetDemo2 {
    public static void main(String[] args) {
        HashSet<Student2> student2s = new HashSet<>();

        //创建学生对象
        Student2 s1 = new Student2("小王", 18);
        Student2 s2 = new Student2("小白", 17);
        Student2 s3 = new Student2("小懒猫", 19);
        Student2 s4 = new Student2("小王", 18);

        //将学生对象添加到集合中
        student2s.add(s1);
        student2s.add(s2);
        student2s.add(s3);
        student2s.add(s4);
        //遍历
        for (Student2 s:student2s){
            System.out.println(s);
        }
    }
}
结果:
Student{name='小王', age=18}
Student{name='小白', age=17}
Student{name='小懒猫', age=19}

public class HashSet implements Set

public class LinkedHashSet extends HashSet implements Set,

LinkedHashSet:

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

2、哈希表保证元素的唯一

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

4、线程不安全,效率高

一般不会去用因为线程不安全

import java.util.LinkedHashSet;

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

        //添加元素到集合
        set1.add("hello");
        set1.add("world");
        set1.add("java");
        set1.add("bigdata");
        set1.add("hadoop");
        set1.add("world");
        set1.add("java");
        set1.add("hello");
        set1.add("spark");
        set1.add("spark");
        set1.add("hbase");
        set1.add("flink");
        set1.add("java");
        set1.add("hello");
//遍历:
        for (String s:set1){
            System.out.println(s);
        }
    }
}
结果:
hello
world
java
bigdata
hadoop
spark
hbase
flink

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

两种排序方式:

自然排序

比较器排序

A NavigableSet实现基于TreeMap 。

的元件使用其有序natural ordering ,或由Comparator集合创建时提供,这取决于所使用的构造方法。

为什么会进行去重以及排序呢?怎么排序呢?看源码。

import java.util.TreeSet;

public class TreeSetDemo1 {
    public static void main(String[] args) {
        TreeSet<Integer> treeSet = new TreeSet<>();
        treeSet.add(20);
        treeSet.add(18);
        treeSet.add(24);
        treeSet.add(23);
        treeSet.add(88);
        treeSet.add(16);
        treeSet.add(12);
        treeSet.add(18);
        treeSet.add(20);
        treeSet.add(23);
        treeSet.add(1);
        treeSet.add(2);
        //遍历:
        for (Integer i:treeSet){
            System.out.println(i);
        }
    }

}
结果:
1
2
12
16
18
20
23
24
88

源码分析:

public abstract class AbstractCollection<E> implements Collection<E>{}
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E>{}
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>{
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
}

public TreeSet() {
        this(new TreeMap<E,Object>());
}

public boolean add(E e) {
        //E -- Integer
        //e -- 20
        return m.put(e, PRESENT)==null;
}

}
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>{
private transient Entry<K,V> root;
public TreeMap() {
        comparator = null;
}


public V put(K key, V value) {
    //key -- 20,18
    //value -- new Object()
    Entry<K,V> t = root;

    //判断根有没有元素,如果没有根,把当前元素值作为根结点。
    if (t == null) {
        compare(key, key); // type (and possibly null) check

        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }

    int cmp; //0
    Entry<K,V> parent; //null
    // split comparator and comparable paths
    //由于我们使用的是无参构造方法,comparator的值是null
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        //key -- 18
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            //向下转型
            //要想这里可以顺利进行向下转型,元素的数据类型必须要实现Comparable接口
            Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}
}

图解:

存储学生对象并遍历

按照正常的写法,我们一运行就报错了

java.lang.ClassCastException:类转换异常

由于我们这里TreeSet创建的时候使用的是无参构造构造方法,走的是自然排序

而这里底层源码中有一步是向下转型的

Comparable k = (Comparable) key;

报错了

原因是我们Student3类没有实现Comparable接口,无法进行向下转型,所以报错了。

创建Student3类:

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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student3 o) {
        //        return 0;
//        return 1;
//        return -1;
        //这里返回什么,应该是根据我们自己定义的规则来排序
        //比如说我想在去重的前提下,按照年龄进行排序。
//        return this.age - o.age;
        //年龄一样,姓名不一定一样
        //这里要区主次条件(主要条件是业务明确给出的,次要条件是我们自己分析得出的)
        int i = this.age - o.age;
        //判断姓名是否一样(三目运算符)
        int i2 = i == 0 ? this.name.compareTo(o.name) : i;
        return i2;
    }
}

创建TreeSet类:

public class TreeDemo2 {
    public static void main(String[] args) {
        TreeSet<Student3> set = new TreeSet<>();
        Student3 s1 = new Student3("theshy", 20);
        Student3 s2 = new Student3("xiaohu", 24);
        Student3 s3 = new Student3("uzi", 25);
        Student3 s4 = new Student3("卡萨", 22);
        Student3 s5 = new Student3("rookie", 23);
        Student3 s6 = new Student3("姿态", 21);
        Student3 s7 = new Student3("faker", 25);
        Student3 s8 = new Student3("xiaohu", 24);
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        set.add(s6);
        set.add(s7);
        set.add(s8);
        for (Student3 s:set){
            System.out.println(s);
        }
    }
}
结果:
Student{name='theshy', age=20}
Student{name='姿态', age=21}
Student{name='卡萨', age=22}
Student{name='rookie', age=23}
Student{name='xiaohu', age=24}
Student{name='faker', age=25}
Student{name='uzi', age=25}

需求:TreeSet集合存储学生对象,并且以姓名的长度来排序

创建Student类

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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student3 o) {
        //        return 0;
//        return 1;
//        return -1;
        //这里返回什么,应该是根据我们自己定义的规则来排序
        //比如说我想在去重的前提下,按照年龄进行排序。
//        return this.age - o.age;
        //年龄一样,姓名不一定一样
        //这里要区主次条件(主要条件是业务明确给出的,次要条件是我们自己分析得出的)
        int i = this.age - o.age;
        //判断姓名是否一样(三目运算符)
        int i2 = i == 0 ? this.name.compareTo(o.name) : i;
        return i2;
    }
}

创建Tree类

import java.util.TreeSet;

public class TreeSetDemo3 {
    public static void main(String[] args) {
//创建TreeSet集合对象
        TreeSet<Student4> set = new TreeSet<>();
        //创建学生对象
        Student4 s1 = new Student4("mingwang", 18);
        Student4 s2 = new Student4("wangyu", 19);
        Student4 s3 = new Student4("zhoujiaxiang", 17);
        Student4 s4 = new Student4("zhangbaogui", 18);
        Student4 s5 = new Student4("liuzhicheng", 18);
        Student4 s6 = new Student4("wangyu", 20);
        //添加到集合里
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        set.add(s6);
        for (Student4 s:set){
            System.out.println(s);
        }
    }
}
结果:
Student{name='wangyu', age=19}
Student{name='wangyu', age=20}
Student{name='mingwang', age=18}
Student{name='liuzhicheng', age=18}
Student{name='zhangbaogui', age=18}
Student{name='zhoujiaxiang', age=17}

比较器排序

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

TreeSet(Comparator comparator)

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

创建学生类

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

    public Student5() {
    }

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

创建MyComparator类

import java.util.Comparator;
public class MyComparator implements Comparator<Student5> {
    @Override
    public int compare(Student5 o1, Student5 o2) {
        //        return 0;
        //主要条件:姓名的长度排序
        int i = o1.getName().length() - o2.getName().length();
//        return i;
        //长度一样,姓名内容不一定一样
        int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
        //姓名内容一样,年龄的大小不一定一样
        int i3 = i2 == 0 ? o1.getAge() -o2.getAge() : i2;

        return i3;
    }
}

创建TreeDemo类

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

public class TreeDemo4 {
    public static void main(String[] args) {
//        MyComparator mc = new MyComparator();
//        TreeSet<Student5> set = new TreeSet<>(mc);
        //匿名内部类实现Comparator接口
        //创建学生对象
        //匿名内部类实现Comparator接口
        TreeSet<Student5> set = new TreeSet<>(new Comparator<Student5>() {

                @Override
                public int compare(Student5 o1, Student5 o2) {
                    //        return 0;
                    //主要条件:姓名的长度排序
                    int i = o1.getName().length() - o2.getName().length();
//        return i;
                    //长度一样,姓名内容不一定一样
                    int i2 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
                    //姓名内容一样,年龄的大小不一定一样
                    int i3 = i2 == 0 ? o1.getAge() -o2.getAge() : i2;

                    return i3;
            }
        });
        Student5 s1 = new Student5("mingwang", 18);
        Student5 s2 = new Student5("wangyu", 19);
        Student5 s3 = new Student5("zhoujiaxiang", 17);
        Student5 s4 = new Student5("zhangbaogui", 18);
        Student5 s5 = new Student5("liuzhicheng", 18);
        Student5 s6 = new Student5("wangyu", 20);

        //将学生对象添加到集合中
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        set.add(s6);

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


    }
}
结果:
Student{name='wangyu', age=19}
Student{name='wangyu', age=20}
Student{name='mingwang', age=18}
Student{name='liuzhicheng', age=18}
Student{name='zhangbaogui', age=18}
Student{name='zhoujiaxiang', age=17}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值