java学习--day18(TreeSet底层&内部类)

文章目录

昨天总结:

复制代码
ArrayList:就是单纯的add
LinkedList: 也是单纯的add
HashSet: 不单纯 得重写equals 和hashCode 方法
TreeSet:不单纯  得在类中去实现Comparable这个接口  让类具有比较排序功能
开发中使用ArrayList

资料:

数据结构学习:http://data.biancheng.net/view/192.html

java8官方文档:https://www.matools.com/api/java8

1.二叉树的了解

复制代码
通过查阅API我们得知TreeSet集合是基于TreeMap的实现,而TreeMap是基于二叉树(红黑树)结构,也就是说TreeSet集合的底层使用的二叉树(红黑树)结构。

树结构:它也是数据结构中的一种。在计算机领域中树结构指的是倒立的树。

树结构存储的数据,每个数据也需要节点来保存。

而TreeSet集合底层是二叉树的数据结构,什么是二叉树呢?

二叉树:每个节点的下面最多只能有2个子节点。

说明:最多表示一个节点下面可以有两个子节点或者一个子节点或者没有子节点。

在二叉树的根节点左侧的节点称为左子树,在根节点的右侧的节点称为右子树。

既然已经得知TreeSet集合底层是二叉树,那么二叉树是怎样存储数据的呢?是怎样保证存储的数据唯一并有序的呢?

二叉树的存储流程:

当存储一个元素的时候,如果是树的第一个元素,这个元素就作为根节点。

如果不是第一个元素,那么就拿要存储的元素与根节点进行比较大小:

大于根元素:就将要存储的元素放到根节点的右侧,作为右叶子节点。

等于根元素:丢弃。

小于根元素:就将要存储的元素放到根节点的左侧,作为左叶子节点。

总结:二叉树是通过比较大小来保证元素唯一和排序的。
20  10  31  5  13  23 51

案例:

​ 使用TreeSet存储Employee对象,比较两个属性

​ int age, int weight 先按照年龄进行升序排,如果年龄相等的话,按照体重升序排

java 复制代码
package com.qfedu.a_treeset;

import java.util.Set;
import java.util.TreeSet;

class Employee implements Comparable<Employee>{
    String name;
    int age;
    int weight;

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

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

    @Override
    public int compareTo(Employee o) {
        //先按照年两比,如果年龄相等 就比较体重
        int num = this.age - o.age;
        if (num == 0) {
            int num1 = o.weight - this.weight;
            return num1;
        }
        return num;
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Set<Employee> set = new TreeSet<>();
        set.add(new Employee("广坤", 35, 78));
        set.add(new Employee("二贝", 26, 70));
        set.add(new Employee("赵四", 35, 72));
        set.add(new Employee("彩云", 35, 79));
        set.add(new Employee("鸡哥", 32, 59));
        set.add(new Employee("正经博", 32, 59));
        System.out.println(set);
    }
}

案例:

​ TreeSet里面存的是Dog类,

​ 两个属性: String name, int age

​ 先按照字符串的字典顺序排,然后字符串相等的话,在按照年龄排

字符串也有compareTo方法,按字典顺序比较两个字符串。 比较是基于字符串中每个字符的Unicode值

java 复制代码
package com.qfedu.a_treeset;

import java.util.Set;
import java.util.TreeSet;

class Dog implements Comparable<Dog>{
    String name;
    int age;

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

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

    @Override
    public int compareTo(Dog o) {
        //先按照字典的顺序进行排,如果字符串相等再按照年龄升序排
        int num = this.name.compareTo(o.name);
        if (num == 0) {
            //字符串相等的情况,又要比较年领
            int num1 = this.age - o.age;
            return num1;

        }
        return num;
    }
}
public class Demo3 {
    public static void main(String[] args) {
        Set<Dog> set = new TreeSet<>();
        set.add(new Dog("彩云", 5));
        set.add(new Dog("旺财", 2));
        set.add(new Dog("大黄", 6));
        set.add(new Dog("大黄", 3));
        set.add(new Dog("大黄", 4));
        System.out.println(set);
    }
}

总结:使用TreeSet的时候需要类实现一个接口 Comparable这个接口去做比较排序

但是就只有这一种方式进行排序吗?不是的!!!还有一种比较器的写法Comparator这个接口

2.使用比较器将数据存储到TreeSet中

java 复制代码
package com.qfedu.b_comparator;

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

class Student {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
class MyComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        int num = o1.age - o2.age;
        return num;
    }
}
public class Demo1 {
    public static void main(String[] args) {
        //如果想要使用比较器的写法 必须再new TreeSet的时候
        //加上比较器对象
        //TreeSet 有一个有参构造,有参构造的方法是Comparwator的对象
        //Comparator是一个接口 不能实例化,咋办?再写一个类去实现这个接口
        Set<Student> students = new TreeSet<>(new MyComparator());
        students.add(new Student("维一", 23));
        students.add(new Student("永康", 19));
        students.add(new Student("赵娜", 18));
        students.add(new Student("运铎", 28));
        students.add(new Student("佳祥", 36));
        System.out.println(students);
    }
}

3.匿名内部类

为了减少代码量

3.1基于抽象类的匿名内部类
java 复制代码
package com.qfedu.c_anno;

//声明一个抽象列类
abstract class Person {
    public abstract void eat();
    public void sleep() {
        System.out.println("好想逃,然后去睡觉!!!");
    }
}
//常规来讲,新建一个类 去继承抽象类。然后实例化继承的抽象类的类
//class Man extends Person {
//
//    @Override
//    public void eat() {
//        System.out.println("好饿,想吃肉!!!");
//    }
//}
public class Demo1 {
    public static void main(String[] args) {
        //匿名内部类:在实例化对抽象类同时并重写抽象方法
        Person person = new Person(){
            @Override
            public void eat() {
                System.out.println("吃吃喝喝");
            }
        };
        person.eat();
        person.sleep();

    }
}
java 复制代码
package com.qfedu.c_anno;

abstract class Animal{
    public abstract void call();
    public abstract void call1();
    
}
public class Demo2 {
    public static void main(String[] args) {
        new Animal(){
            @Override
            public void call() {
                System.out.println("哇哇叫!!!");
            }

            @Override
            public void call1() {
                System.out.println("哈哈叫");
            }
        }.call();
        new Animal(){
            @Override
            public void call() {
                System.out.println("哇哇叫!!!");
            }

            @Override
            public void call1() {
                System.out.println("哈哈叫");
            }
        }.call1();
    }
}
3.2基于接口的匿名内部类
java 复制代码
package com.qfedu.c_anno;

interface A {
    void testA();

}
public class Demo3 {
    public static void main(String[] args) {
//        A a = new A(){
//
//            @Override
//            public void testA() {
//                System.out.println("嘻嘻哒");
//            }
//        };
//        a.testA();
        new A(){

            @Override
            public void testA() {
                System.out.println("哈哈");
            }
        }.testA();
    }
}
java 复制代码
package com.qfedu.c_anno;

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

class Student {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Demo4 {
    //存到TreeSet里面
    public static void main(String[] args) {
        Set<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
               int num =  o1.age - o2.age;
                return num;
            }
        });
        set.add(new Student("维一", 23));
        set.add(new Student("永康", 19));
        set.add(new Student("赵娜", 18));
        set.add(new Student("运铎", 28));
        set.add(new Student("佳祥", 36));
        System.out.println(set);
    }
}

真实开发的时候,一个方法参数是一个接口对象,不用再新建一个类去实现这个接口,直接方法中去new 接口

java 复制代码
package com.qfedu.c_anno;

interface B {
    void eat();
}
public class Demo5 {
    public static void main(String[] args) {
        test(new B() {
            @Override
            public void eat() {
                System.out.println("吃锦旗");
            }
        });
    }
    public static void test (B b) {
        b.eat();
    }
}

4.内部类

从字面意思来理解:在类的内部创建一个类,这个类叫内部类
了解即可,开发禁止使用(效率太低)

4.1成员内部类

在类的方法的外面再类中,就是成员内部类

java 复制代码
package com.qfedu.d_inner;

class MemberDemo {
    String name = "张三";
    int age = 20;

    public void printf() {
        System.out.println("打印着玩");
    }
    class Inner {//就是内部类
        String name = "李四";
        //在Inner这个类中可以访问外部类的属性和方法
        public void test () {
            printf();//打印着玩
            System.out.println(age);//20
            System.out.println(name);//李四
            //如果访问外部特定的属性的时候: 类名.this.属性
            System.out.println(MemberDemo.this.name);//张三
        }
    }

}
public class Demo1 {
    public static void main(String[] args) {
        //成员内部类的创建步骤:
        //1.实例化外部类 类对象
        MemberDemo memberDemo = new MemberDemo();
        //2.实例化内部类对象,但是new得改为  外部对象.new
        MemberDemo.Inner inner = memberDemo.new Inner();
        inner.test();

    }
}
相关推荐
专注API从业者7 分钟前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠25 分钟前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
keep one's resolveY1 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端
天空属于哈夫克31 小时前
企业微信API常见的错误和解决方案
java·数据库·企业微信
摇滚侠2 小时前
VMvare 虚拟机 Oracle19c 安装步骤,远程连接 Oracle19c,百度网盘安装包
java·oracle
梁萌2 小时前
idea报错找不到XX包的解决方法
java·intellij-idea·启动报错·缺少包
Agent产品评测局2 小时前
生产排期与MES/ERP系统打通,实操方法详解 —— 2026企业级智能体自动化选型与实战指南
java·运维·人工智能·ai·chatgpt·自动化
阿丰资源3 小时前
基于Spring Boot的电影城管理系统(直接运行)
java·spring boot·后端
呱牛do it3 小时前
企业级门户网站设计与实现:基于SpringBoot + Vue3的全栈解决方案(Day 8)
java
消失的旧时光-19434 小时前
Spring Boot 工程化进阶:统一返回 + 全局异常 + AOP 通用工具包
java·spring boot·后端·aop·自定义注解