8.1 异常的类型
异常的根类型:java.lang.Throwable,它有两大子类:Error和Exception。
Error:指合理的应用程序不去捕获的严重的错误。例如:VirtualMachineError虚拟机错误,包含StackOverflewError(栈内存溢出)和OutOfMemoryError(堆内存错误)。
Exception:指合理的应用程序试图捕获的异常。
ArrayIndexOutOfBoundsException数组下标越界异常 当发生这个异常,一定是[下标]超过[0, 数组的长度-1]范围。
NullPointerException空指针异常 当发生这个异常时,一定是 .前面的对象是null,或者是数组名[下标]中数组是null。
ClassCastException类型转换异常 当发生这个异常时,一定是向下转型出问题。
InputMisMatchException输入不匹配异常 输入的数据不符合要接收的数据的类型。
....
编译时异常(受检异常):无论这个异常是否真的会发生,只要可能发生,编译器会在编译时就给出“警示”,要求程序员必须处理该异常,要么暂时throws,要么try-catch,否则编译不通过。
运行时异常(非受检异常):无论这个异常是否真的会发生,哪怕真的会发生(百分百会发生),编译器也不给你任何提示。
但是,无论是编译时异常还是运行时异常,一旦真的发生了,如果没有try-catch进行处理,都会导致程序崩溃。如果当前方法没处理,当前方法先挂掉,JVM会把异常转交给调用者,如果调用者也不处理,调用者也会挂掉,如果一直到main方法都没有try-catch处理,就会导致程序挂掉。
8.2 5个关键字
1、try-catch
try{
可能发生异常的代码
}catch(异常的类型1e){
e.getMessage()获取异常信息
e.printStackTrace() 打印异常对象的详细跟踪信息
其他处理异常的代码
}catch(异常的类型2e){
//....
}
//JDK1.7之后
try{
可能发生异常的代码
}catch(异常的类型1|异常类型2e){//当两种或更多种异常的处理方式一样,就可以使用同一个catch分支,不同异常类型之间使用 | 分割
e.getMessage()获取异常信息
e.printStackTrace() 打印异常对象的详细跟踪信息
其他处理异常的代码
}catch(异常的类型3e){
//....
}
(1)如果多个catch分支的异常类型没有父子类关系,顺序随意。
(2)如果多个catch分支的异常类型有父子类关系,子类型在上父类型在下。
(3)try中如果没有异常,所有的catch都不会执行。
(4)try中如果有异常,根据异常对象的类型,从上往下匹配catch分支,一旦匹配就进入这个catch分支,下面的catch就不执行了。如果所有的catch都不匹配,相当于异常没有处理,当前方法就会挂掉,JVM会把异常转交给调用者。
2、try-catch-finally
try{
可能发生异常的代码
}【catch(异常的类型1e){
e.getMessage()获取异常信息
e.printStackTrace() 打印异常对象的详细跟踪信息
其他处理异常的代码
}catch(异常的类型2e){
//....
}】finally{
上面的try中无论是否发生异常,也不管有没有catch分支,能不能捕获try中发生的异常,
哪怕try或catch中有return语句,都不能阻止finally块的执行。一般用于编写资源释放的代码。
}
3、throw
在构造器或方法体中,用于手动抛出一个异常对象。
throw异常对象;
thrownew异常类型(【实参列表】);
4、throws
【修饰符】构造名(【形参列表】) throws异常类型列表{
}
【修饰符】返回值类型方法名(【形参列表】) throws异常类型列表{
}
只要当前构造器或当前方法中可能发生xx异常,但是在当前构造器或方法中又没有进行“try-catch"处理,希望调用者处理,就可以通过throws声明出来,告诉调用者当前构造器或方法可能发生xx类型的异常。
8.3 自定义异常
1、必须继承Throwable或者子类。通常我们都继承RuntimeException 或 Exception比较多。
继承RuntimeException:表示该自定义异常类型是运行时异常类型,编译器就不会提示。
继承Exception:表示该自定义异常类型是编译时异常类型,一旦throw new 了,编译器就会提示你要处理该异常。
2、建议自定义异常类型时,保留多个构造器,便于创建异常对象。
8.4 方法重载与方法重写对比
方法的重载Overload | 方法的重写Override | |
位置 | 同一个类中 或 父子类中 | 父子类 |
方法名 | 必须相同 | 必须相同 |
形参列表 | 必须不同 | 必须相同 |
返回值类型 | 无关 | (1)基本数据类型和void:必须相同(2)引用数据类型:<= |
权限修饰符 | 不看 | >=,不能是子类不可见private |
其他修饰符 | 不看 | 不能是static、final |
throws 异常列表 | 不看 | (1)被重写方法如果没有声明“throws 编译时异常类型”,那么重写时就不能声明“throws 编译时异常类型”。(2)被重写方法如果有声明“throws 编译时异常类型”,那么重写时可以不继续声明“throws 编译时异常类型”,也可以继续throws,但是throws后面的编译时异常类型<=父类throws声明的编译时异常类型。(3)关于“throws 运行时异常类型” 不做限制。 |
8.5 this和super关键字总结
this | 说明 | super | 说明 | ||
意义 | this是一个变量,引用当前对象的变量 | 仅仅是一个关键字 | |||
类型 | 编译时类型 | this在哪个类中它的编译时类型就是哪个类 | this当前编译时类型的父类或父接口 | ||
运行时类型 | 在构造器中,表示正在new的对象;在实例方法中,表示调用当前方法的对象 | this当前编译时类型的父类或父接口 | |||
使用位置 | 不允许在静态成员中出现 | 同左 | |||
使用形式 | 独立使用 | 可以 | 不可以 | ||
引用构造器 | this()或this(实参列表),匹配本类的构造器 | 只能在构造器首行 | super()或super(实参列表),匹配直接父类的构造器 | 只能在子类构造器首行,只要构造器首行没有this()或this(实参列表)、super()或super(实参列表),就默认有super() | |
引用变量 | this.成员变量 | 先从本类寻找成员变量,找不到也会逐级从父类声明的权限修饰符允许的成员变量列表寻找,编译时找到谁,执行时就是谁 | super.成员变量 | 直接逐级从父类声明的权限修饰符允许的成员变量列表寻找,编译时找到谁,执行时就是谁 | |
引用方法 | this.成员方法 | 先从本类寻找成员方法,找不到也会逐级从父类声明的权限修饰符允许的成员方法列表寻找,编译时找到谁,运行时执行谁要看this对象具体是哪个类对象,如果this代表子类对象,要看子类是否重写了该方法,如果重写了,就执行重写方法。 | super.成员方法 | 直接逐级从父类声明的权限修饰符允许的成员方法列表寻找,编译时找到谁,执行时就是谁 | |
其他 | 外部类.this.xx | 当内部类的成员与外部类的非静态成员重名时使用 | 父接口.super.方法 | 当父接口的默认方法与父类的某方法重名,或当多个父接口的默认方法重名时使用 |