day11.内部类_异常
今日重点:
1.能分清编译时期异常和运行时期异常
2.会使用throws处理异常
3.会使用try...catch处理异常
4.知道我们最终为啥要使用try...catch处理异常
5.知道Object是谁
6.知道Object中的toString方法作用以及重写toString方法之后的作用
7.知道Object中的equals方法作用以及重写equals方法之后的作用
第一章.内存
1.this和super
2.static关键字内存图
第二章.异常
1.异常介绍
1.概述:代码出现了不正常的现象,在java中每一个异常都是java的一个一个的类,或者叫做异常对象
2.异常体系说明:
Throwable:
Error:错误 -> 好比是人得了癌症 -> 不能通过处理让代码变正常了,必须重新写
Exception:异常(所有异常的父类) -> 好比是人得了感冒(能治) -> 可以通过处理,让代码变得正常
a.编译时期异常:代码一写,jvm一编译,报红了 -> Exception以及Exception的子类(除了RuntimeException以及RuntimeException的子类)
b.运行时期异常:代码写的时候没事,但是已运行就报错(RuntimeException以及子类)
public class Demo01Exception {
public static void main(String[] args){
//Error
//int[] arr1 = new int[999999999];//java.lang.OutOfMemoryError
//运行时期异常
int[] arr2 = new int[3];
System.out.println(arr2[3]);//ArrayIndexOutOfBoundsException
/*
编译时期异常->
不是我们写的语法错误,
而是人家底层给我们抛了一个编译时期异常对象,底层抛出的异常继承自Exception
我们一用就出现了编译时期异常
*/
//FileOutputStream fos = new FileOutputStream("day11_exception\\1.txt");
}
}
1.ctrl+n -> 搜索所有的类(包括自己写的以及java提前定义好的)
2.异常出现的过程
3.创建异常对象(了解)
创建异常对象,是为了故意造异常,以便我们后续学处理异常
1.格式:
throw new 异常对象()
public class Demo03Exception {
public static void main(String[] args) {
String s = "abc.txt";
method(s);
}
public static void method(String s) {
if (!s.endsWith(".txt")){
//创建异常对象
throw new NullPointerException();
}
}
}
4.异常处理方式(重点)
4.1 异常处理方式一_throws
1.格式:在参数后面
throws 异常
public class Demo04Exception {
public static void main(String[] args)throws FileNotFoundException {
String s = "abc.txt1";
/*
method方法使用了throws异常处理方案
往上抛异常,但是抛的是编译时期异常
此异常让调用处接收了
也就是说:method(s)接收了一个下面抛过来的编译时期异常
所以此处爆红
*/
add(s);
System.out.println("删除功能");
System.out.println("修改功能");
System.out.println("查询功能");
}
public static void add(String s)throws FileNotFoundException {
if (!s.endsWith(".txt")){
//创建异常对象
throw new FileNotFoundException();
}
System.out.println("我要执行");
}
}
4.2 异常处理方式一_throws多个异常
1.格式:
throws 异常1,异常2
2.注意:
如果处理的多个异常之间,有子父类继承关系,我们可以直接抛父类异常
如果不知道多个异常之间到底有没有子父类继承关系,我们可以直接抛Exception
public class Demo05Exception {
public static void main(String[] args)throws /*FileNotFoundException,*//*IOException*/Exception {
String s = "abc.txt1";
/*
method方法使用了throws异常处理方案
往上抛异常,但是抛的是编译时期异常
此异常让调用处接收了
也就是说:method(s)接收了一个下面抛过来的编译时期异常
所以此处爆红
*/
add(s);
}
public static void add(String s)throws /*FileNotFoundException,*//*IOException*/Exception {
if (s==null){
//创建异常对象
throw new IOException("IO异常了");
}
if (!s.endsWith(".txt")){
//创建异常对象
throw new FileNotFoundException("文件找不到异常");//利用有参构造设置异常信息
}
System.out.println("我要执行");
}
}
4.3 异常处理方式二_try…catch
1.格式:
try{
可能会出现异常的代码
}catch(异常类型 对象名){
处理异常的方案->开发中将异常信息保存到日志文件中
}
public class Demo06Exception {
public static void main(String[] args) {
String s = "abc.txt1";
try {
//String s1 = null;
//System.out.println(s1.length());//NullPointerException
add(s);
}catch (FileNotFoundException e){
//如果try中的异常抓不到,try...catch外面的功能会受影响
e.printStackTrace();//将异常详细信息打印出来
}
System.out.println("删除功能");
System.out.println("修改功能");
System.out.println("查询功能");
}
private static void add(String s) throws FileNotFoundException {
if (!s.endsWith(".txt")) {
throw new FileNotFoundException("文件找不到");
}
System.out.println("我要执行");
}
}
4.4 异常处理方式二_多个catch
1.格式:
try{
可能会出现异常的代码
}catch(异常类型 对象名){
处理异常的方案->开发中将异常信息保存到日志文件中
}catch(异常类型 对象名){
处理异常的方案->开发中将异常信息保存到日志文件中
}catch(异常类型 对象名){
处理异常的方案->开发中将异常信息保存到日志文件中
}...
2.注意:
a.如果多个异常之间有子父类继承关系,先抓子类,再抓父类异常
b.如果多个异常之间有子父类继承关系,我们可以直接抓父类异常
public class Demo07Exception {
public static void main(String[] args) {
String s = "abc.txt1";
/*try {
add(s);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}*/
//错误演示
/*try {
add(s);
}catch (IOException e){
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}*/
/*try {
add(s);
}catch (IOException e){
e.printStackTrace();
}*/
try {
add(s);
}catch (Exception e){
e.printStackTrace();
}
}
public static void add(String s) throws FileNotFoundException, IOException {
if (s == null) {
//创建异常对象
throw new IOException("IO异常了");
}
if (!s.endsWith(".txt")) {
//创建异常对象
throw new FileNotFoundException("文件找不到异常");//利用有参构造设置异常信息
}
System.out.println("我要执行");
}
}
5.finally关键字
1.作用:一定会执行的代码块
2.使用:都是和try结合使用
public class Demo08Exception {
public static void main(String[] args) {
String s = "abc.txt1";
try {
method(s);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
System.out.println("我一定要执行,爱谁谁!");
}
}
public static void method(String s)throws FileNotFoundException{
if (!s.endsWith(".txt")){
throw new FileNotFoundException("文件找不到异常");
}
}
}
//结果:
// java.io.FileNotFoundException: 文件找不到异常
// 我一定要执行,爱谁谁!
//流程:
// try: 接受method方法抛出异常,执行catch捕获异常并执行异常,最终执行finally代码
public class Demo08Exception {
public static void main(String[] args) {
String s = "abc.txt1";
try {
String s1 = null;
System.out.println(s1.length());//NullPointerException
method(s);
}catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
System.out.println("我一定要执行,爱谁谁!");
}
}
public static void method(String s)throws FileNotFoundException{
if (!s.endsWith(".txt")){
throw new FileNotFoundException("文件找不到异常");
}
}
}
//结果:
// 我一定要执行,爱谁谁!
// java.lang.NullPointerException
//流程:
// try: 接收到s1变量操作出现异常,去catch:查看对于异常类型处理方案结果没有。进行往下执行finally代码。jvm发现还没有处理异常终止程序并将异常信息打印出来
public class Demo09Exception {
public static void main(String[] args) {
int result = method();
System.out.println(result);
/*
执行顺序:
程序入门是main方法
调用method()执行method()方法
执行try代码里
定义空字符串赋值给变量s
调用变量s的属性-》发现出现错误是“空指针异常”
jvm捕获异常执行到catch里发现return关键字(结束当前方法) 下面finally关键字执行不
如果执行catch代码会导致程序结束,没办法执行到finally
所以先执行finally代码,后在去执行catch代码
结果:
我一定要执行
1
*/
}
public static int method() {
try {
String s = null;
System.out.println(s.length());//空指针异常
return 2;
} catch (Exception e) {
return 1;
} finally {
System.out.println("我一定要执行");
}
}
}
finally的使用场景:关闭资源
堆内存中的对象由GC(垃圾回收器)回收,但是有很多对象,如:IO流对象,网编 Socket对象,数据库连接对象(Connection)等,GC无法回收,既然GC没有办法回收,我们只能自己关闭资源,销毁对象,所以我们可以将关闭资源,销毁对象的操作放到finally中
6.抛异常时注意的事项(扩展)
1.父类中的方法抛了异常了,那么子类重写此方法之后要不要抛呢?
可抛可不抛
2.父类中的方法没有抛异常,那么子类重写此方法之后要不要抛呢?
不要抛
7.try_catch和throws的使用时机
1.如果处理异常之后,还想让后续的代码正常执行,我们使用try...catch
2.如果方法之间是递进关系(调用),我们可以先throws,但是到了最后需要用try...catch做一个统一的异常处理
1.运行时期异常一般我们不处理,因为一旦有运行时期异常出现,肯定是代码写的有问题
2.编译时期异常我们肯定要处理,不处理爆红,代码爆红了,不处理还继续往下写,没意义
8.自定义异常
1.需求:键盘录入一个用户名,实现登录功能,如果登录失败,抛出LoginUserException
public class Demo11Exception {
public static void main(String[] args) throws LoginUserException {
//1.创建Scanner对象
Scanner scanner = new Scanner(System.in);
System.out.println("请您输入要登录的用户名:");
String username = scanner.next();
//2.定义一个字符串,代表已经注册过的用户名
String name = "root";
//3.判断
if (username.equals(name)){
System.out.println("登录成功");
}else{
//如果失败了,就创建异常对象
throw new LoginUserException("登录失败");
}
}
}
public class LoginUserException extends Exception /*RuntimeException*/{
public LoginUserException() {
}
public LoginUserException(String message) {
super(message);
}
}
1.创建一个类
a.继承Exception,此时变成了编译时期异常
b.继承RuntimeException,此时变成了运行时期异常
2.提供构造方法,方便我们设置异常信息
9.打印异常信息的三个方法
Throwable中的方法:
public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误信息)
public String toString():获取异常的类型和异常描述信息(不用)
public void printStackTrace():打印异常的跟踪栈信息并输出到控制台上(最详细的异常信息)
public class Demo12Exception {
public static void main(String[] args) {
String s = "abc.txt1";
try {
method(s);
} catch (FileNotFoundException e) {
//System.out.println(e.getMessage());
//System.out.println(e.toString());
e.printStackTrace();
}
}
public static void method(String s)throws FileNotFoundException{
if (!s.endsWith(".txt")){
throw new FileNotFoundException("文件找不到异常");
}
}
}
第三章.Object类
1.Object的介绍
1.概述:
所有类的父类,根类,所有的类都会直接或者间接去继承Object类
2.注意:
a.一个类如果没有明确写出extends xxx,那么此类默认的亲爹就是Object
2.Object类中的toString方法
小技巧:
1.按住ctrl不放,鼠标点击被调用的方法或者变量,可以快速跳到对应的方法以及变量的位置
2.ctrl+n 查询类
3.alt+7 查看当前类中的成员
1.Object中的toString方法 -> 返回对象的字符串表示形式
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
2.结论:
a.如果一个类没有重写toString方法,直接输出对象名会默认调用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;
}
//重写toString
@Override
public String toString() {
return name+","+age;
}
}
public class Test01 {
public static void main(String[] args) {
Person p1 = new Person("柳岩",36);
Person p2 = new Person("涛哥",18);
System.out.println(p2);
System.out.println(p1.toString());//com.atguigu.b_object.Person@135fbaa4
System.out.println(p2.toString());//com.atguigu.b_object.Person@45ee12a7
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add("def");
System.out.println(list);// [abc, def]
}
}
结论:
1.如果直接输出对象名,不让其输出地址值,就在此对象中重写toString方法,让toString返回内容
2.怎么重写:
alt+insert->toString->ok
3.Object类中的equals方法
1.Object中的equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
2.注意:
==:
a.针对于基本类型,比较的值
b.针对于引用类型,比较的是地址值
3.结论:
a.如果没有重写Object中的equals方法,那么会调用Object中的equals方法,针对引用类型比较地址值
b.如果重写Object中的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;
}
//重写toString
/* @Override
public String toString() {
return name+","+age;
}*/
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/**
*
* @param obj
* @return
*
* 问题1:为啥用obj调用name和age报错? 因为此时obj为Object类型接收了Person类型的p2
* 此处为多态,name和age是Person中的特有属性,多态前提下,不能直接调用子类特有成员,所以报错
* 解决问题1:
* 向下转型
*
* 问题2:如果传递的不是Person类型,会出现类型转换异常
* 解决问题2:加个类型判断,如果传递过来的数据属于Person类型,在强转成Person类型
*
* 问题3:如果equals方法接收的是null,我们就没有必要判断类型了
* 解决问题3:直接做非空判断,提高点效率
*
* 问题4:如果equals方法接收的是自己,就会出现自己和自己比较,自己跟自己比肯定为true,就没有必要
* 判断类型,向下转型,比较了
* 解决问题4:加判断,如果地址值一样,直接返回true
*
*/
/*public boolean equals(Object obj){
if (this==obj){
return true;
}
if (obj==null){
return false;
}
if (obj instanceof Person){
Person p2 = (Person)obj;
return this.name.equals(p2.name) && this.age == p2.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);
}
}
public class Test02 {
public static void main(String[] args) {
Person p1 = new Person("柳岩",36);
Person p2 = new Person("柳岩",36);
//System.out.println(p1.equals(p2));
//ArrayList<String> list = new ArrayList<>();
//System.out.println(p1.equals(list));
//System.out.println(p1.equals(null));
System.out.println(p1.equals(p1));
System.out.println("=========================");
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2));//true
System.out.println(s1==s2);//false
}
}
结论:
1.如果比较两个对象,想比较对象的内容,就重写equals方法
2.怎么重写:alt+insert -> equals and hashCode -> 一路下一步->ok