模块十三 异常_Object

回顾与重点

模块十二回顾

  1. 权限修饰符:

    public → protected → 默认 → private

    a. 构造一般用public:便于new对象

    b. 成员方法一般用public:便于调用

    c. 属性一般用private:封装思想

  2. final:最终的

    a. 修饰类:不能被继承

    b. 修饰方法:不能被重写

    c. 修饰局部变量:不能二次赋值

    d. 修饰对象:地址值不能改变,但是对象中的属性值可以改变

    e. 修饰成员变量:需要手动赋值,不能二次赋值

  3. 代码块:

    a. 构造代码块:

    { }
    

    优先于构造方法执行,每new一次,构造代码块就执行一次

    b. 静态代码块:

    static {  }
    

    优先于构造代码块和构造方法执行,只执行一次。

    静态代码块 > 构造代码块 > 构造方法 → 从执行顺序上来看

  4. 匿名内部类:

    a. 格式1:

    new 接口/抽象类() {
    	重写方法	
    }.重写的方法名();
    

    b. 格式2:

    接口/抽象类 对象名 = new 接口/抽象类() {
      重写的方法
    }
    对象名.重写的方法名();
    

模块十三重点

  1. 分清楚什么是编译时期异常,什么是运行时期异常
  2. 知道处理异常的两种方式
  3. 知道finally关键字的使用场景
  4. 知道Object是啥
  5. 知道Object中toString以及equals方法的使用
  6. 知道重写Object中的toString以及equals方法的作用

第一章 API文档

  1. 什么叫做API: Application Programming Interface,简称API,又称之为应用编程接口。

    即,定义出来的类以及接口,以及其中的方法等。

  2. 为了方便我们去查询开发好的接口以及类,以及其中的方法,会对应提供一个文档 → API文档

  3. API文档作用:查询我们要使用的对象,以及方法,是我们程序员的”字典“

    设置任务栏快捷菜单

    img

JDK API文档使用

image-20240407145620091

image-20240407150414854

image-20240407161810640

第二章 异常

2.1 异常介绍

概述:代码出现了不正常的现象;在Java中,异常就是一个一个的类

image-20240408181336855

image-20240408182129306

public class Demo01Exception {
    public static void main(String[] args) {
         // 错误 Error → StackOverflowError
        // method();

        // 运行时期异常 → ArrayIndexOutOfBoundsException
        int[] arr1 = new int[3];
        // System.out.println(arr1[4]);

        /*
            编译时期异常
            注意看:编译时期异常是我们代码写错了吗?不是,当我调用方法的时候,该方法底层给我们抛了一个编译时期异常,
            所以导致我们一编译,就爆红
            当我们一旦触发这个异常,jvm就会将异常信息打印到控制台上,给程序员们看
         */
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = "2000-10-10 10:10:10";
        // Date date = simpleDateFormat.parse(time);
        // System.out.println(date);

    }
    public static void method() {
        method();
    }
}

2.2 异常出现的过程

public class Demo02Exception {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        method(arr);
    }
    public static void method(int[] arr) {
        System.out.println(arr[6]);
        System.out.println("我想要行");
    }
}

image-20240407195957922

2.3 创建异常对象(了解)

创建异常对象只是为了后面学习如何处理异常,其他的暂时没有啥意义。

  1. 关键字:throw
  2. 格式:throw new 异常
public class Demo03Exception {
    public static void main(String[] args) {
        String s = "a.tx1t";
        method(s);
    }
    public static void method(String s) {
        if (!s.endsWith(".txt")) {
            // 故意创建异常对象,用throw说明此处有异常
            throw new NullPointerException();
        }
        System.out.println("我要被执行了");
    }
}

2.4 异常处理方式(重点)

2.4.1 异常处理方式一_throws

  1. 格式:在方法参数和方法体之间位置上写

    throw 异常
    
  2. 意义:处理异常

    将异常异常往上抛

import java.io.FileNotFoundException;

public class Demo04Exception {
    public static void main(String[] args) throws FileNotFoundException {
        String s = "a.txt1";
        add(s); // 添加功能
        delete(); // 删除功能
        update(); // 修改功能
        find(); // 查询功能
    }
    private static void add(String s) throws FileNotFoundException {
        System.out.println("添加功能");
        if (!s.endsWith(".txt")) {
            // 故意制造异常
            throw new FileNotFoundException("文件找不到");
        }
        System.out.println("文件执行了");
    }

    private static void find() {
        System.out.println("查询功能");

    }

    private static void update() {
        System.out.println("修改功能");
    }

    private static void delete() {
        System.out.println("删除功能");
    }
}

image-20240407204335666

image-20240407204038340

2.4.2 异常处理方式一_throws多个异常

  1. 格式:throw 异常1,异常2…

    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class Demo05Exception {
        public static void main(String[] args) throws FileNotFoundException, IOException {
            String s = "a.txt1";
            add(s); // 添加功能
            delete(); // 删除功能
            update(); // 修改功能
            find(); // 查询功能
        }
        private static void add(String s) throws FileNotFoundException, IOException {
            System.out.println("添加功能");
            if (s==null) {
                // 故意制造异常
                throw new IOException("IO异常");
            }
            if (!s.endsWith(".txt")) {
                // 故意制造异常
                throw new FileNotFoundException("文件找不到");
            }
            System.out.println("文件执行了");
        }
    
        private static void find() {
            System.out.println("查询功能");
    
        }
    
        private static void update() {
            System.out.println("修改功能");
        }
    
        private static void delete() {
            System.out.println("删除功能");
        }
    }
    

    两个异常不能同时触发

  2. 注意:

    如果throws的多个异常之间有子父类继承关系,我们可以直接throws父类异常;

    如果不知道多个异常之间是否存在有子父类继承关系,我们可以直接throws Exception。

    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class Demo05Exception {
        public static void main(String[] args) throws /*FileNotFoundException, IOException*/ Exception {
            String s = "a.txt1";
            add(s); // 添加功能
            delete(); // 删除功能
            update(); // 修改功能
            find(); // 查询功能
        }
        private static void add(String s) throws /*FileNotFoundException, IOException*/ Exception {
            System.out.println("添加功能");
            if (s==null) {
                // 故意制造异常
                throw new IOException("IO异常");
            }
            if (!s.endsWith(".txt")) {
                // 故意制造异常
                throw new FileNotFoundException("文件找不到");
            }
            System.out.println("文件执行了");
        }
    
        private static void find() {
            System.out.println("查询功能");
    
        }
    
        private static void update() {
            System.out.println("修改功能");
        }
    
        private static void delete() {
            System.out.println("删除功能");
        }
    }
    

2.4.3 异常处理方式二_try…catch

  1. 格式

    try {
      可能出现异常的代码
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    }
    
    import java.io.FileNotFoundException;
    
    public class Demo06Exception {
        public static void main(String[] args) {
            String s = "a.txt1";
            try {
                /*
                    try...catch没有捕获到的异常,最终会由jvm处理,并终止程序
                 */
                /*int[] arr = null;
                System.out.println(arr.length); // NullPointerException*/
                add(s); // 添加功能
            } catch (Exception exception) {
                System.out.println(exception);
            }
    
            delete(); // 删除功能
            update(); // 修改功能
            find(); // 查询功能
        }
        private static void add(String s) throws FileNotFoundException {
            System.out.println("添加功能");
            if (!s.endsWith(".txt")) {
                // 故意制造异常
                throw new FileNotFoundException("文件找不到");
            }
            System.out.println("文件执行了");
        }
    
        private static void find() {
            System.out.println("查询功能");
        }
    
        private static void update() {
            System.out.println("修改功能");
        }
    
        private static void delete() {
            System.out.println("删除功能");
        }
    }
    

    处理当前异常之后,之后的程序正常运行

2.4.4 异常处理方式二_多个catch

  1. 格式:

    try {
      可能出现异常的代码
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    }...
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class Demo07Exception {
        public static void main(String[] args) {
            String s = "a.txt1";
            try {
                add(s); // 添加功能
            } catch (FileNotFoundException foundException) {
                System.out.println(foundException);
            } catch (IOException ioException) {
                System.out.println(ioException);
            }
            delete(); // 删除功能
            update(); // 修改功能
            find(); // 查询功能
        }
        private static void add(String s) throws FileNotFoundException, IOException {
            System.out.println("添加功能");
            if (s==null) {
                // 故意制造异常
                throw new IOException("IO异常");
            }
            if (!s.endsWith(".txt")) {
                // 故意制造异常
                throw new FileNotFoundException("文件找不到");
            }
            System.out.println("文件执行了");
        }
    
        private static void find() {
            System.out.println("查询功能");
    
        }
    
        private static void update() {
            System.out.println("修改功能");
        }
    
        private static void delete() {
            System.out.println("删除功能");
        }
    }
    

    image-20240407221749948

  2. 注意:

    如果catch的多个异常之间有子父类继承关系,我们可以直接catch父类异常

    如果不知道多个异常之间是否有子父类继承关系,我们也可以直接catch Exception。

    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class Demo07Exception {
        public static void main(String[] args) {
            String s = "a.txt1";
            /*try {
                add(s); // 添加功能
            } catch (FileNotFoundException foundException) {
                System.out.println(foundException);
            } catch (IOException ioException) {
                System.out.println(ioException);
            }*/
            try {
                add(s); // 添加功能
            } catch (Exception exception) {
                exception.printStackTrace(); // 将详细的异常信息打印到控制台上
            }
            delete(); // 删除功能
            update(); // 修改功能
            find(); // 查询功能
        }
        private static void add(String s) throws FileNotFoundException, IOException {
            System.out.println("添加功能");
            if (s==null) {
                // 故意制造异常
                throw new IOException("IO异常");
            }
            if (!s.endsWith(".txt")) {
                // 故意制造异常
                throw new FileNotFoundException("文件找不到");
            }
            System.out.println("文件执行了");
        }
    
        private static void find() {
            System.out.println("查询功能");
    
        }
    
        private static void update() {
            System.out.println("修改功能");
        }
    
        private static void delete() {
            System.out.println("删除功能");
        }
    }
    

2.5 finally关键字

  1. 概述:代表的是不管是否触发了异常,都会执行的代码

    特殊情况:如果之前执行了 System.exit(0) 终止当前正在执行的Java虚拟机

  2. 使用:都是配合 try...catch 使用

    try {
      可能出现异常的代码
    } catch (异常 对象名) {
      处理异常的代码 → 将来开发会将异常信息保存到日志文件中
    } finally {
      不管是否有异常都会执行的代码
    }
    
    import java.io.FileNotFoundException;
    
    public class Demo08Exception {
        public static void main(String[] args) {
            String s = "a.txt1";
            try {
                add(s); // 添加功能
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } finally {
                System.out.println("我必须得执行");
            }
        }
        private static void add(String s) throws FileNotFoundException {
            System.out.println("添加功能");
            if (!s.endsWith(".txt")) {
                // 故意制造异常
                throw new FileNotFoundException("文件找不到");
            }
            System.out.println("文件执行了");
        }
    }
    
    public class Demo09Exception {
        public static void main(String[] args) {
            int result = method();
            System.out.println(result);
        }
    
        private static int method() {
            try {
                String s = null;
                System.out.println(s.length()); // 空指针异常
                return 2;
            } catch (Exception e) {
                return 1; // return 1 代表的是将1返回,结束方法
            } finally {
                System.out.println("我一定要执行");
                // return 3; // 返回3,结束代码,所以不返回1了
            }
        }
    }
    

    image-20240407224314494

    当 finally里面得return 3 打开注释时,返回3,结束代码,所以不返回1了

    finally的使用场景

    1. 关闭资源

    2. 原因:对象如果没有用了,GC(垃圾回收器)回收,用来回收堆中的垃圾,但是有一些对象GC回收不了,比如:连接对象(Connection)、IO流对象、Socket对象,这些对象GC回收不了,就需要我们自己手动回收,手动关闭。

      将来不能回收的对象new完之后,后续操作不管是否操作成功,是否有异常,我们都需要手动关闭,此时我们就可以将关闭资源的代码放到finally中。

      import java.io.FileWriter;
      import java.io.IOException;
      
      public class Test {
          public static void main(String[] args) {
              FileWriter fw = null;
              try {
                  fw = new FileWriter("day13_exception_object\\1.txt");
                  fw.write("哈哈哈");// 假如这里写失败或者写成功了
              } catch (IOException e) {
                  throw new RuntimeException(e);
              } finally {
                  if (fw != null) {
                      try {
                          fw.close();
                      } catch (IOException e) {
                          throw new RuntimeException(e);
                      }
                  }
              }
          }
      }
      

2.6 抛异常时注意的事项

  1. 如果父类中的方法抛了异常,那么子类重写之后要不要抛?

    可抛可不抛

  2. 如果父类中的方法没有抛异常,那么子类重写之后要不要抛?

    不要抛

public class Demo10Exception {
    public static void main(String[] args) {

    }
    class A{
        public void method() /*throws Exception*/ {

        }
    }
    class B extends A{
        @Override
        public void method() /*throws Exception*/ {

        }
    }
}

2.7 try…catch和throws的使用时机

  1. 如果处理异常之后,还想让后续的代码正常运行,我们使用 try...catch

  2. 如果方法之间时递进关系(调用),我们可以先用 throws ,但是到了最后需要用 try...catch 做一个统一的异常处理

    image-20240408010439676

    1. 编译时期异常,必须要处理,不处理报错(报红),没法运行

      a. throws

      b. try…catch

    2. 运行时期异常我们一般不处理,因为一旦出现运行时期异常异常,肯定是代码编写有问题,我们直接修改代码细节。

2.8 自定义异常

需求:键盘录入一个用户名,实现登录功能,如果登录失败,抛出LoginUserException

  1. 定义一个类
  2. 如果继承Exception就是编译时期异常
  3. 如果继承RuntimeException就是运行时期异常
public class LoginUserException extends Exception {
    public LoginUserException() {}

    public LoginUserException(String message) {
        super(message);
    }
}
import java.util.Scanner;

public class Demo11Exception {
    public static void main(String[] args) throws LoginUserException {
        // 1. 定义一个用户名,代表已经注册的用户
        String name = "root";
        // 2. 创建Scanner对象,录入用户名
        Scanner sc = new Scanner(System.in);
        System.out.println("请您输入需要登录的用户名");
        String userName = sc.next();
        // 3. 判断用户名是否和已经存在的用户名一致
        if (name.equals(userName)) {
            System.out.println("您已经登陆成功了");
        } else {
            throw new LoginUserException("登录失败了,用户名或者密码有问题");
        }
    }
}

2.9 打印异常信息的三个方法

Throwable类中的方法:

String toString()	→ 输出异常类型
String getMessage() → 输出的是异常信息
void printStackTrace() → 打印异常信息是最全的:包括异常类型、信息、以及出现的行数等等
public class LoginUserException extends Exception {
    public LoginUserException() {}

    public LoginUserException(String message) {
        super(message);
    }
}
public class Demo11Exception {
    public static void main(String[] args) {
        // 1. 定义一个用户名,代表已经注册的用户
        String name = "root";
        // 2. 创建Scanner对象,录入用户名
        Scanner sc = new Scanner(System.in);
        System.out.println("请您输入需要登录的用户名");
        String userName = sc.next();
        // 3. 判断用户名是否和已经存在的用户名一致
        if (name.equals(userName)) {
            System.out.println("您已经登陆成功了");
        } else {
            try {
                throw new LoginUserException("登录失败了,用户名或者密码有问题");
            } catch (Exception e) {
                System.out.println(e.toString());
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}

image-20240408012831592

第三章 Object类

概述:所有类的根类(父类),所有的类都会直接或者间接继承Object类

3.1 Object中的toString

  1. Object中的toString方法:返回该对象的字符串表示形式

    public String toString() {
      return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    
  2. 注意:

    a. 如果没有重写Object中的toString方法,直接输出对象名会默认调用Object中的toString方法,直接输出地址值。

    b. 如果重写了Object中的toString方法,在输出地址值,重写没有意义,所以重写完toString之后,应该返回对象的内容。

    public class Person {
        private String name;
        private int age;
        public Person() {}
        public Person(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 "Person [name=" + name + ", age=" + age + "]";
        }
    }
    
    public class Test01 {
        public static void main(String[] args) {
            Person p1 = new Person("金莲", 26);
            System.out.println(p1); // com.atguigu.b_object.Person@3b07d329 ,重写之后,输出的内容不再是地址值 Person [name=金莲, age=26]
            // 调用的是Object类中的toString,重写之后,输出的内容不再是地址值 Person [name=金莲, age=26]
            System.out.println(p1.toString()); // com.atguigu.b_object.Person@3b07d329
    
            System.out.println("================");
            ArrayList<String> list = new ArrayList<>();
            list.add("张三");
            list.add("李四");
            list.add("王五");
            // 调用的是AbstractCollection中的toString,重写过Object中的toString
            System.out.println(list.toString()); // [张三, 李四, 王五]
        }
    }
    

    快速生成toString

    alt + insert → 选择toString → 直接下一步

  3. 总结:

    如果直接输出对象名不想输出地址值,就重写Object中的toString方法。

3.2 Object中的equals

  1. 概述: 比较的是两个地址之是否相等

    public boolean equals(Object obj) {
      return (this == obj);
    }
    /*
    	== 针对于基本数据类型来说,比较的是值
    	== 针对于引用数据类型来说,比较的是地址值
    */
    
  2. 注意:

    a. 如果没有重写Object中的equals方法,那么就会调用Object中的equals方法,比较对象的地址值

    b. 如果重写了Object中的equals方法,那么就会调用重写后的equals方法,应该比较对象的内容

    public class Person {
        private String name;
        private int age;
        public Person() {}
        public Person(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 "Person [name=" + name + ", age=" + age + "]";
        }
    }
    
    public class Test02 {
        public static void main(String[] args) {
            Person p1 = new Person("金莲", 26);
            Person p2 = new Person("金莲", 26);
            System.out.println(p1==p2); // false
            System.out.println(p1.equals(p2)); // false
        }
    }
    

    image-20240408092652273

    小结:

    1. 如果直接输出对象名不想输出地址值,重写toString方法
    2. 如果想比较两个对象的内容,就重写一下equals方法
    3. 怎么重写:alt+insert → 选 toString 或者equals and hascode → 啥也不要管 → 一路下一步即可

3.3 Object中的clone方法

  1. 作用:复制一个属性值一样的新对象

  2. 使用:

    需要被克隆的对象实现Cloneable

    重写clone方法

    public class Person implements Cloneable {
        private String name;
        private int age;
        public Person() {}
        public Person(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 "Person [name=" + name + ", age=" + age + "]";
        }
        /*
            问题1:obj直接调用name和age调用不了,因为object接收了Person对象,
                   属于多态,多态前提下不能直接调用子类特有内容
            解决问题1:向下转型
    
            问题2:如果传递的不是Person类型,就会出现类型转换异常
            解决问题2:先判断类型,如果是Person类型,再强转成Person类型
    
            问题3:如果传递null,就不用判断类型了,直接给false
            问题4:如果传递自己呢?就不用判断非空了,也不用判断类型了,直接给true
         */
        /*@Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (obj instanceof Person) {
                Person person = (Person) obj;
                return this.name.equals(person.name)&&this.age==person.age;
            }
            return false;
        }*/
    
        @Override
        public boolean equals(Object object) {
            if (this == object) return true;
            if (object == null || getClass() != object.getClass()) return false;
            Person person = (Person) object;
            return age == person.age && Objects.equals(name, person.name);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    public class Test03 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person = new Person("涛哥", 16);
            Object object = person.clone();
            Person person1 = (Person) object; // 克隆一个新对象
            System.out.println(person==person1); // 比较地址值 false
            System.out.println(person.equals(person1)); // true
        }
    }
    

第四章 经典接口

4.1 java.lang.Comparable

我们知道基本类型的数据(除boolean类型外)需要比较大小的话,之间使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?

Java给所有引用数据类型的大小比较,指定了一个标准接口,就是 java.lang.Comparable 接口:

package java.lang;
public interface Comparable{
  int compareTo(Object obj);
}

那么我们想要使得我们某个类的对象可以比较大小,怎么做呢?步骤:

第一步:哪个类的对象要比较大小;哪个类就实现 java.lang.Comparable 接口,并重写方法

  • 方法体就是你要如何比较当前对象和指定的另外一个对象的大小

第二步:对象比较大小时,通过对象调用 compareTo 方法,根据方法的返回值决定谁大谁小

  • this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)大于0,返回正整数
  • this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)大于0,返回负整数
  • this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)等于0,返回零

代码示例:

public class Student implements Comparable {
    private String name;
    private int score;

    public Student() {
    }
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
    /*
        this:代表students[j]
        o:代表students[j+1]

        如果students[j].getScore() - students[j+1].getScore() > 0
        证明数组中前面一个对象比后面一个对象的分数高

     */
    @Override
    public int compareTo(Object o) {
        if (o instanceof Student) {
            Student s = (Student) o;
            return this.getScore() - s.getScore();
        }
        return 0;
    }
}

测试类

public class Test01 {
    public static void main(String[] args) {
        // 创建一个数组
        Student[] students = new Student[3];
        students[0] = new Student("张三", 100);
        students[1] = new Student("李四", 60);
        students[2] = new Student("王五", 80);
        for (int i = 0; i < students.length-1; i++) {
            for (int j = 0; j < students.length-1-i; j++) {
                // 如果students[j]比students[j+1]大,就排序换序
                if (students[j].compareTo(students[j+1])>0) {
                    Student temp = students[j];
                    students[j] = students[j+1];
                    students[j+1] = temp;
                }
            }
        }
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
    }
}

image-20240408120602234

4.2 java.util.Comparator

思考:

(1) 如果一个类,没有实现Comparable接口,而两个类你又不方便修改(例如:一些第三方的类,你只有.class文件,没有源文件),那么这样类的对象也要比较大小,怎么办?

(2) 如果一个类,实现了Comparable接口,也指定了两个对象的比较大小规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?

JDK在设计库之初,也考虑到这种情况了,所以又增加了一个 java.util.Comparator 接口。

package java.util;

public interface Comparator {
  int compare(Object o1, Object o2);
}

那么我们想要比较某个类的两个对象的大小,怎么办呢?步骤:

第一步:编写一个类,我们称之为比较器类型,实现 java.util.Comparator 接口,并重写方法

  • 方法体就是你要如何指定的两个对象的大小

第二步:比较大小是,通过比较器类型的对象调用compare()方法,将要比较大小的两个对象作为compare方法的实参传入,根据方法的返回值大小决定谁大谁小。

  • o1对象减o2对象大于0,返回正整数
  • o1对象减o2对象小于0,返回负整数
  • o1对象减o2对象等于0,返回零
public class Student implements Comparator {
    private String name;
    private int score;

    public Student() {
    }
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
    /*
        o1:代表students[j]
        o2:代表students[j+1]

        如果o1的分数大于o2的分数 → compare方法返回正整数
        如果o1的分数小于o2的分数 → compare方法返回负整数
        如果o1的分数等于o2的分数 → compare方法返回零
     */
    @Override
    public int compare(Object o1, Object o2) {
        Student s1 = (Student) o1;
        Student s2 = (Student) o2;
        return s1.getScore() - s2.getScore();
    }
}
public class Test01 {
    public static void main(String[] args) {
        // 创建一个数组
        Student[] students = new Student[3];
        students[0] = new Student("张三", 100);
        students[1] = new Student("李四", 60);
        students[2] = new Student("王五", 80);
        Student student = new Student();
        for (int i = 0; i < students.length-1; i++) {
            for (int j = 0; j < students.length-1-i; j++) {
                // 如果students[j]比students[j+1]大,就排序换序
                if (student.compare(students[j], students[j+1])>0) {
                    Student temp = students[j];
                    students[j] = students[j+1];
                    students[j+1] = temp;
                }
            }
        }
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
    }
}

第五章 总结

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/527374.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何从iPhone恢复已删除的照片

这些照片是我们今天生活中最珍贵的回忆。它们捕捉了我们一生珍惜的时刻。但是&#xff0c;丢失这些记忆可能是毁灭性的&#xff0c;尤其是在不小心从iPhone中删除它们时。 幸运的是&#xff0c;有一些方法可以从iPhone恢复已删除的照片。在这篇博文中&#xff0c;我们将讨论从…

【opencv】示例-detect_mser.cpp 使用 MSER 算法来检测图像中的极值区域

#include <opencv2/core.hpp> // 包含OpenCV核心操作的头文件 #include <opencv2/imgproc.hpp> // 包含图像处理功能的头文件 #include <opencv2/highgui.hpp> // 包含图形用户界面的头文件 #include <opencv2/features2d.hpp> // 包含特征检测相关功能…

【数据结构】考研真题攻克与重点知识点剖析 - 第 5 篇:树与二叉树

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图与王道考研课程&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术…

C# + OpencvSharp4 错误信息收集

异常1&#xff1a; 初次使用&#xff0c;如下代码报错&#xff0c;OpenCvSharp.OpenCvSharpException:“imread failed.” Mat src Cv2.ImRead("Source.png", ImreadModes.Unchanged); 原因&#xff1a;检查Nuget包与OpencvSharp4库相关安装是否完整&#xff0c;…

虚拟地址的设置与应用全攻略

在计算机网络和操作系统中&#xff0c;虚拟地址是一个核心概念&#xff0c;它允许程序在逻辑上拥有连续的内存空间&#xff0c;而无需关心实际的物理内存布局。虚拟地址的引入极大地简化了程序的开发和内存管理&#xff0c;提高了系统的灵活性和安全性。虎观代理将详细解析虚拟…

Spring Boot中整合JodConverter实现文件在线预览

Spring Boot中整合JodConverter实现文件在线预览 1.安装LibreOffice 24.2 下载地址 LibreOffice 是一款功能强大的办公软件&#xff0c;默认使用开放文档格式 (OpenDocument Format , ODF), 并支持 *.docx, *.xlsx, *.pptx 等其他格式。 它包含了 Writer, Calc, Impress, Dra…

java基于微服务的智慧工地管理云平台SaaS源码 数据大屏端 APP移动端

目录 智慧工地云平台概述 智慧工地功能 &#xff08;项目端&#xff09; 一、劳务管理&#xff1a; 二、施工安全管理&#xff1a; 三、视频监控管理&#xff1a; 四、机械安全管理&#xff1a; 五、施工质量管理&#xff1a; 六、绿色文明施工&#xff1a; 七、施工综…

CSS3如何实现雷达扫描图(动态样式)

动态样式控制雷达扫描和暂停&#xff1a; //html部分&#xff1a; <view class"radar" :style"{--state:animationPlayState}"></view>data部分&#xff1a; animationPlayState: paused, methods: changeStatus(){this.animationPlayState …

Failed to start docker.service: Unit is not loaded properly: Invalid argument.

Failed to start docker.service: Unit is not loaded properly: Invalid argument. 未知原因&#xff1a;docker服务无法正常load 解决方式&#xff1a; 卸载docker&#xff0c; 删除docker.service 重新安装docker Docker是一种相对使用较简单的容器&#xff0c;我们可以通过…

证书生成和获取阿里云备案获取密钥流程

1.在java文件夹下 输入 cmd 打开命令行窗口 2. keytool -genkey -alias 证书名 -keyalg RSA -keysize 2048 -validity 36500 -keystore 证书名.keystore 输入这一行&#xff0c;把证书名三个字 改成 项目的名称&#xff08;例如&#xff1a;D23102802&#xff09; 3. 密码默认填…

【会议】Oracle自动化运维峰会

2023年7月21日&#xff0c;杭州。我组织了Oracle自动化运维峰会&#xff0c;大约有20人左右参加会议。以下是会议主题&#xff1a; Oracle自动化运维能力是Oracle 19c自动化运维体系中非常重要的一环&#xff0c;自动化索引、自动化SQL优化、资源隔离等技术能够非常好的提升运维…

备考ICA----Istio实验17---TCP流量授权

备考ICA----Istio实验17—TCP流量授权 1. 环境准备 1.1 环境部署 kubectl apply -f <(istioctl kube-inject -f istio/samples/tcp-echo/tcp-echo.yaml) -n kim kubectl apply -f <(istioctl kube-inject -f istio/samples/sleep/sleep.yaml) -n kim1.2 测试环境 检测…

使用Python将多张图片转换为动态GIF图像

在本文中&#xff0c;我们将学习如何使用Python编写代码&#xff0c;将多张静态图片转换为一个动态的GIF图像。无论你的图片格式是JPEG&#xff08;.jpg&#xff09;还是PNG&#xff08;.png&#xff09;&#xff0c;我们都将使用Python中的PIL库来实现这一功能。通过本文的学习…

k8s_入门_命令详解

命令详解 kubectl是官方的CLI命令行工具&#xff0c;用于与 apiserver进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为 apiserver能识别的信息&#xff0c;进而实现管理k8s各种资源的一种有效途径 1. 帮助 2. 查看版本信息 3. 查看资源对象等 查看No…

精品PPT-数据治理总体解决方案新版(免费下载)

1、知识星球下载&#xff1a; 如需下载完整PPTX可编辑源文件&#xff0c;请前往星球获取&#xff1a;https://t.zsxq.com/19F4dDDrv 2、免费领取步骤&#xff1a; 【1】关注公众号 方案驿站 【2】私信发送 数据治理新版 【3】获取本方案PDF下载链接&#xff0c;直接下载即可…

【C++】手搓 list 容器

送给大家一句话&#xff1a; 若结局非你所愿&#xff0c;就在尘埃落定前奋力一搏。—— 《夏目友人帐》 手搓 list 容器 1 前言1.1 底层结构1.2 使用场景1.3 功能简介 2 框架搭建2.1 节点类2.2 list 类2.3 迭代器类 3 功能实现3.1 begin() 与 end()3.2 插入操作3.3 删除操作3…

云原生之旅第一课(2站搜索K8s成神之路)

自己动手搭建Kubernetes集群&#xff0c;学习如何自定义CRD&#xff0c;以及使用Kubebuilder快速搭建Operator项目&#xff0c;云原生之旅第一课。从一开始准备录制课程&#xff0c;到如今已经有了500位忠实粉丝&#xff0c;我感到无比欣慰。这门课程完全开源&#xff0c;每一集…

FPN网络

FPN&#xff08;Feature Pyramid Network&#xff09;是一种用于目标检测和语义分割等计算机视觉任务的网络结构。它旨在解决不同尺度下的特征信息不足的问题&#xff0c;提高模型对小目标和远距离目标的检测能力。在目标检测任务中&#xff0c;由于目标的尺度和形状各异&#…

聚观早报 | 百度文心一言上线新功能;腾势Z9GT将发布

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月08日消息 百度文心一言上线新功能 腾势Z9GT将发布 华为将举办鸿蒙春季沟通会 苹果与Shutterstock达成协议 O…

ebpf+perfetto实现调度延迟记录与展示

1.背景 需要分析生产环境的调度问题,如线程的调度延迟有多少,在哪些时间点延迟比较明显,影响其调度的主要原因是什么?其次,我们希望可以比较直观的展示调度延迟情况。最好能对接perfetto的UI和后处理,因为perfetto已经用于分析比较多的性能数据,可以和调度数据进行整合.我们…