CoderArchiveDay12 (2025.5.25) 异常与Object类

还是先总结一下上一个模块

接下来进入模块十三
异常

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

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

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

由上图可以看出,异常有一套责任链机制,若不处理虚拟机会不断向上抛出异常,直到被处理.

简单了解创建异常的方法

注意,这里的NullPointerException是运行时异常而非编译时期异常,后者必须要有相关的显性处理方式,而前者则没有这样的要求(默认如果运行时出了异常没有处理方法的话就向上抛,但是不写处理方法编译期也不会报错)

下图是编译时异常若不处理会报错的实例:

这里就看出try-catch方法的优越性了,不仅负责任,而且被精准捕获并处理的异常不会影响后方代码的继续运行.

然后是finally代码块

示例代码:

package main.java.com.exception;

public class Demo09Exception {
    public static void main(String[] args) {
        int result = method();
        System.out.println(result);
    }

    public static int method() {
        try {
            String s = "hello";
            System.out.println(s.length());//空指针异常
            return 2;
        } catch (Exception e) {
            return 1;
        } finally {
            System.out.println("我一定要执行");
            return 3;
        }
    }
}

最终输出是

5
我一定要执行
3

finally的霸权:

finally的使用场景:

1.关闭资源

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

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

示例代码:

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

  }
}
}

有关继承的异常抛出原理:

记住:

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

可抛可不抛

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

不要抛

已经解释得很详细了,不再赘述.

总之,一定要负责任,不能一直向上throws直到返回给用户,必须在中途处理掉,至少也要在返回到用户的最后一层处理掉异常.

自定义异常也非常简单

接下来进入奥博杰克特类(Object类)的内容部分

Object类

需要注意的是,重写的toString方法可以在类中用alt+insert快速生成:

接下来是equals方法

同样的,可以用alt+insert键快速生成自定义类的重写的equals方法,会考虑到所有情况,只有当自己跟自己比较以及自定义类的字段都相同时才会返回true,否则返回false.

这一部分应当直接上源码:

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

    /*
       问题1:obj直接调用name和age调用不了,因为Object接收了Person类型的对象
            属于多态,多态前提下不能直接调用子类特有内容
       解决问题1:向下转型

       问题2:如果传递的不是Person类型,就会出现类型转换异常
       解决问题2:先判断类型,如果是Person类型,再强转成Person

       问题3:如果传递null呢?,就不用判断类型了,直接给false

       问题4:如果传递自己呢?就不用判断非空了,也不同判断类型了,直接给true
     */
   /* public boolean equals(Object obj){
        if (this==obj){
            return true;
        }

        if (obj==null){
            return false;
        }

        if (obj instanceof Person){
            Person p = (Person) obj;
            return this.name.equals(p.name)&&this.age==p.age;
        }
        return false;

    }*/

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

以自定义的Person类为例,可以看到合理的equals方法应当考虑几种情况,当传递的Obj对象不是Person类或者为null时,直接返回false;如果类型相同,则将o向下强转成Person类型(这里是为了规避多态情况下无法使用子类特有成员的限制)后对属性值进行比较.一定要熟稔这里的经典源码.

String类已经重写好了equals方法,可以直接比较字符串内容.

最后了解一下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
     */
   /* public boolean equals(Object obj){
        if (this==obj){
            return true;
        }

        if (obj==null){
            return false;
        }

        if (obj instanceof Person){
            Person p = (Person) obj;
            return this.name.equals(p.name)&&this.age==p.age;
        }
        return false;

    }*/

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test03 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p2 = new Person("涛哥", 16);
        Object o = p2.clone();
        Person p3 = (Person) o;//克隆了一个新对象

        System.out.println(p2==p3);//比较地址值  false
        System.out.println(p2.equals(p3));//true
    }
}

接下来是拓展知识,对于引用数据类型的比较,Java有两个接口

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[i]
      o:代表students[i+1]

      如果students[i].getScore()-students[i+1].getScore()>0
         证明数组中的前面一个对象比后面一个对象的分数高
     */
    @Override
    public int compareTo(Object o) {
        Student s = (Student) o;
        return this.getScore()- s.getScore();
    }
}

测试类:

public class Test01 {
    public static void main(String[] args) {
        //创建一个数组
        Student[] students = new Student[3];
        Student s1 = new Student("张三", 100);
        Student s2 = new Student("李四", 60);
        Student s3 = new Student("王五", 80);
        students[0] = s1;
        students[1] = s2;
        students[2] = s3;

        for (int j = 0; j<students.length-1;j++){
            for (int i = 0;i<students.length-1-j;i++){
                //如果students[i]比students[i+1]大,就排序换位置
                if (students[i].compareTo(students[i+1])>0){
                    Student temp = students[i];
                    students[i] = students[i+1];
                    students[i+1] = temp;
                }
            }
        }

        //遍历
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
    }
}

然后是Comparator(比较器)接口

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[i]
       o2代表students[i+1]

       如果o1的分数大于o2的分数-> compare方法返回正整数
       如果o1的分数小于o2的分数-> compare方法返回负整数
       如果o1的分数等于o2的分数-> compare方法返回0
     */
    @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];
        Student s1 = new Student("张三", 100);
        Student s2 = new Student("李四", 60);
        Student s3 = new Student("王五", 80);
        students[0] = s1;
        students[1] = s2;
        students[2] = s3;

        Student student = new Student();

        for (int j = 0; j<students.length-1;j++){
            for (int i = 0;i<students.length-1-j;i++){
                //如果students[i]比students[i+1]大,就排序换位置
                if (student.compare(students[i],students[i+1])>0){
                    Student temp = students[i];
                    students[i] = students[i+1];
                    students[i+1] = temp;
                }
            }
        }

        //遍历
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
    }
}

注意:Comparator的定义例子中使用了匿名内部类作为返回值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值