【day13】回顾
在深入探讨异常处理与Object类之前,让我们回顾一下【day13】中的关键内容:
-
权限修饰符:
public
:最广的访问范围,任何地方都可以访问。protected
:在同包和子类中可以访问。- 默认(无修饰符):仅在同包内可以访问。
private
:仅在定义它的类内部可以访问。
-
final关键字:
- 修饰类:不能被继承。
- 修饰方法:不能被重写。
- 修饰变量:值不可改变。
- 修饰对象:对象引用不可变,但对象内部状态可变。
-
代码块:
- 构造代码块:在对象构造时执行。
- 静态代码块:在类加载时执行。
-
匿名内部类:
- 一种无需显式声明类名的内部类,常用于简化代码和实现接口。
模块十三重点
本模块我们将深入学习异常处理机制和Object类:
- 理解编译时期异常与运行时期异常的区别。
- 掌握两种异常处理方式:
throws
和try...catch
。 - 了解
finally
关键字的使用场景。 - 了解Object类及其中的
toString
和equals
方法。 - 掌握重写
toString
和equals
方法的重要性。
第一章:API文档
API文档是程序员的“字典”,它详细描述了Java中预定义的类和接口,以及它们的方法和属性,方便我们查询和使用。
第二章:异常
1. 异常介绍
异常是程序运行过程中出现的不正常现象。在Java中,异常都是类的实例。
public class Demo01Exception {public static void main(String[] args) throws ParseException {//错误Error -> StackOverflowError//method();//运行时期异常 -> ArrayIndexOutOfBoundsExceptionint[] 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();}
}
2. 异常处理方式
2.1 throws
关键字
用于在方法签名中声明该方法可能抛出的异常,将异常往上抛
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 {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.2 try...catch
语句
用于捕获和处理异常。
try{可能出现异常的代码}catch(异常 对象名){处理异常的代码-> 将来开发会将异常信息保存到日志文件中}
public class Demo06Exception {public static void main(String[] args){String s = "a.txt1";try{//int[] arr = null;//System.out.println(arr.length);//NullPointerExceptionadd(s);//添加功能}catch (FileNotFoundException e){System.out.println(e);}delete();//删除功能update();//修改功能find();//查询功能}private static void add(String s)throws FileNotFoundException {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.3 finally
关键字
无论是否发生异常,finally
块中的代码都会执行。
特殊情况:如果之前执行了System.exit(0)终止当前正在执行的java虚拟机
public class Demo08Exception {public static void main(String[] args){String s = "a.txt";try {add(s);//添加功能} catch (FileNotFoundException e) {e.printStackTrace();}finally {System.out.println("我必须滴执行");}}private static void add(String s)throws FileNotFoundException {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);}public static int method() {try {String s = null;System.out.println(s.length());//空指针异常return 2;} catch (Exception e) {return 1;} finally {System.out.println("我一定要执行");//return 3;}}
}
finally的使用场景: 关闭资源
原因: 对象如果没有用了,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);}}}}
}
2.4 try...catch
和throws
的使用时机
- 如果处理异常之后,还想让后续的代码正常执行,我们使用try…catch
- 如果方法之间是递进关系(调用),我们可以先throws,但是到了最后需要用try…catch做一个统一的异常处理
3. 自定义异常
可以通过继承Exception
类来创建自定义异常。
需求:键盘录入一个用户名,实现登录功能,如果登录失败,抛出LoginUserException
public class LoginUserException extends Exception{public LoginUserException() {}public LoginUserException(String message) {super(message);}
}
public class Demo11Exception {public static void main(String[] args) throws LoginUserException {//1.定义一个用户名,代表已经注册的用户String username = "root";//2.创建Scanner对象,录入用户名Scanner sc = new Scanner(System.in);System.out.println("请您输入要登录的用户名:");String name = sc.next();//3.判断用户名是否和已经存在的用户名一致if (name.equals(username)){System.out.println("登录成功了");}else{throw new LoginUserException("登录失败了,用户名或者密码有问题");}}
}
-
定义一个类
-
如果继承Exception 就是编译时期异常
-
如果继承
RuntimeException
,就是运行时期异常
4. 打印异常信息的方法
toString()
:输出异常类型和信息。getMessage()
:输出异常信息。printStackTrace()
:打印异常的详细信息,包括异常类型、信息和堆栈跟踪。
public class Demo11Exception {public static void main(String[] args) {//1.定义一个用户名,代表已经注册的用户String username = "root";//2.创建Scanner对象,录入用户名Scanner sc = new Scanner(System.in);System.out.println("请您输入要登录的用户名:");String name = 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();}}}
}
第三章:Object类
Object类是Java中所有类的根类,提供了一些基础方法,如toString
、equals
和hashCode
。
1. toString
方法
- 用于返回对象的字符串表示形式。
- 如果没有重写
toString
方法,直接输出对象会默认调用Object中的toString
方法,输出地址值。 - 如果直接输出对象名不想输出地址值,就重写Object中的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;}@Overridepublic 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@4eec7777System.out.println(p1.toString());//com.atguigu.b_object.Person@4eec7777System.out.println("==============");ArrayList<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");System.out.println(list);//[张三, 李四, 王五]System.out.println(list.toString());//[张三, 李四, 王五]}
}
2. equals
方法
- 用于比较两个对象的地址值是否相等。
- 如果重写了
equals
方法,应该比较对象的内容。
3. clone
方法
用于复制一个属性值相同的新对象。
示例代码
public class Person {private String name;private int age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic 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);}
}public class TestObject {public static void main(String[] args) {Person p1 = new Person("John", 30);System.out.println(p1.toString());System.out.println(p1.equals(new Person("John", 30)));}
}
第四章.经典接口
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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", score=" + score +'}';}/*this:代表students[i]o:代表students[i+1]如果students[i].getScore()-students[i+1].getScore()>0证明数组中的前面一个对象比后面一个对象的分数高*/@Overridepublic 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]);}}
}
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;}@Overridepublic 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*/@Overridepublic 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]);}}
}