面向对象
文章目录
一、继承性extends
1.为什么要有类的继承性,好处是什么?
- 减少代码冗余,减少代码复用性;
- 便于功能的拓展;
- 为多态性的使用,提供了前提。
2.继承性的格式
class A extends B{ }
A:子类、派生类、subclass
B:父类、超类、基类、superclass
3.继承性的说明
- 一个类可以被多个类继承;
- 一个类只能有一个父类(单继承性);
- 子父类是相对概念。直接继承的父类叫直接父类,间接继承的父类叫间接父类;
- 子类拥有所有父类(直接父类,间接父类)中声明的方法及属性(private的则无法继承);
- 子类可以声明自己特有的属性和方法,也可以重写父类中的方法。
4.object类的理解
- 如果我们没显式的声明一个类的父类的话,则此类继承于java.lang.Object类;
- 所的Java类(除java.lang.Object类之外都直接或间接的继承于java.lang.Object类;
- 意味着,所的Java类具有java.lang.Object类声明的功能。
二、重载VS重写
1.怎样才构成重载(overload)?
同一个类中,同一方法名,不同的形参列表(参数个数不同或者参数类型不同),以下四个方法构成重载。
-
简记(两同一不同)
-
子类可以重载父类的方法
public void getSum(int i,int j){
System.out.println("1");
}
public void getSum(double d1,double d2){
System.out.println("2");
}
public void getSum(String s ,int i){
System.out.println("3");
}
public void getSum(int i,String s){
System.out.println("4");
}
以下方法不构成重载
public int getSum(int i,int j){
return 0;
}
public void getSum(int m,int n){
}
private void getSum(int i,int j){
}
2.重写(override或者overwrite)
定义:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。
3.重写的规则
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法。
方法的声明: 权限修饰符 返回值类型 方法名 throws 异常类型{方法体}
-
权限修饰符
-
子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
特殊情况:子类不能重写父类中声明为private权限的方法
-
-
返回值类型
- 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
- 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
- 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
-
方法名
- 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
-
异常类型
- 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
-
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写)
要么都声明为static的(不是重写)。
4.面试题 区分方法的重载与重写?
-
重载形参列表不一样,重写形参列表一样
-
对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为**“早绑定”或“静态绑定”,**
而对于多态,解释运行器运行时才会确定所要调用的具体方法,这称为**“晚绑定”或“动态绑定”。**
引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”
-
重载,编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。
-
重载——不表现为多态性
-
重写——表现为多态性
三、关键字this和super用法
1.this
1.this的语法"this.“和"this()”;
2.this不能出现在静态方法中,this代表对本类对象的引用,指向本类已经创建的对象;静态方法随着类的加载而加载,加载后对象可能未创建;
3.this在区分成员变量与局部变量是不能省略;
4.①我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
② 构造器中不能通过"this(形参列表)“方式调用自己;
③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)”;
④ 规定:"this(形参列表)“必须声明在当前构造器的首行;
⑤ 构造器内部,最多只能声明一个"this(形参列表)”,用来调用其他的构造器。
2.super
1.super的语法"super.“和"super()”;
2.不能出现在静态方法中;
3.当子类中出现和父类一样的属性或者方法,调用父类的那个属性或者方法,“super.”不能省略。
4.我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
"super(形参列表)“的使用,必须声明在子类构造器的首行!
在类的多个构造器中,至少一个类的构造器中使用了"super(形参列表)”,调用父类中的构造器
3.比较
this();和super();都必须声明在构造器中的第一行,所以不能同时存在;
当没有显示this(); 和 super(); 时,默认调用super;
在类的多个构造器中,至少一个类的构造器中使用了"super(形参列表)",调用父类中的构造器
Object对象的无参数构造方法一定会先执行,因为Object是所有类的根类。
如果父类没有无参数的构造器,并且在子类的构造器中有没有显示的调用父类的其他构造器,Java编译器就会报错
四、子类对象实例化的全过程
1.从结果上看:继承性
子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所父类中声明的属性。
2.从过程上看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,…直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所的父类的结构,所以才可以看到内存中父类中的结构,子类对象才可以考虑进行调用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TtOTIwv-1628525247599)(C:\Users\86198\AppData\Roaming\Typora\typora-user-images\1628497470714.png)]
3.强调说明:
虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
五、多态性
1.多态性的理解
一种事物的多种形态
2.何为多态性
对象的多态性:父类的引用指向子类的对象(子类的对象赋值给父类的引用)
举例:
Person p = new Man();
Object o = new Date();
3.多态性的使用:虚拟方法调用
- 在编译期间,只能调用父类中声明的方法,但在运行期间,我们实际执行的是子类重写父类后的方法。
- 总结:编译看左边,运行看右边。
4.多态性使用的前提
- 类的继承关系(继承性)
- 方法的重写
5.多态性的应用举例
public void func(Animal animal){//Animal animal = new Dog();
animal.eat();//调用父类中声明的方法,实际执行子类重写后的方法。
animal.shout();
}
6.多态性使用的注意点
对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
7.为什么使用向下转型?
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。如何才能调用子类特的属性和方法?使用向下转型。
7.1 使用时的注意点:
① 使用强转时,可能出现ClassCastException的异常。
② 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
③ 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。
8.面试题:
8.1 谈谈你对多态性的理解?
① 实现代码的通用性。
② Object类中定义的public boolean equals(Object obj){ }
JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)
③ 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)
8.2 多态是编译时行为还是运行时行为?
六、Object类
1.特性
-
Object类是所Java类的根父类
-
如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
-
Object类中的功能(属性、方法)就具通用性。
- 属性:无
- 方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()
wait() 、 notify()、notifyAll()
-
Object类只声明了一个空参的构造器
2.equals()的使用:
1.是一个方法,而非运算符
2.只能适用于引用数据类型
3.Object类中equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:**Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.**即两个引用是否指向同一个对象实体
像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们
就需要对Object类中的equals()进行重写.(直接调用equals方法Alt+shift+s)
重写的原则:比较两个对象的实体内容是否相同.
3.toString()的使用
1. 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
Object类中toString()的定义:
public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}
像String、Date、File、包装类等都重写了Object类中的toString()方法。
使得在调用对象的toString()时,返回"实体内容"信息
自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"
4.面试题
① final、finally、finalize的区别?
② == 和 equals() 区别?
七、包装类
1.基本数据类型与对应的包装类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mit3NcEX-1628525247601)(C:\Users\86198\AppData\Roaming\Typora\typora-user-images\1628504203209.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9AbDuCHs-1628525247603)(C:\Users\86198\AppData\Roaming\Typora\typora-user-images\1628507119422.png)]
public class Test {
// 基本数据类型-->包装类
Integer a = new Integer(11); //通过构造器装箱
Integer t = 11; //自动装箱
Integer t2 = Integer.valueOf(11);
// 包装类-->基本数据类型
int c = t.intValue(); //调用包装类的方法拆箱
int d = a; //自动拆箱
// String类型-->包装类、基本数据类型
String num4 = "4";
Integer e = Integer.parseInt(num4);
int f = Integer.parseInt(num4);
int num3 = new Integer(num4);
// 包装类、基本数据类型-->String类型
int num5 = 5;
Integer f1 = 3;
String s1 = 5 +"";//法一
String s2 = String.valueOf(num5);//法二
String s3 = f1.toString();
}
Integer内部定义了IntegerCache结构,后者中定义了Integer[],里面保存了-128-127,自动装箱时赋值在此范围内可以直接使用,不再new对象。
八、关键字static
1.static可以修饰属性,方法,代码块,内部类;类中的常量也常常声明为static
2.static修饰属性可以分为:静态变量(类变量)和实例变量(非静态变量)
-
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
-
实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
-
静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用。
-
静态变量的加载要早于对象的创建。
-
由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
-
举例:System.out;Math.PI
3.static修饰方法可以分为:静态方法(类方法)和非静态方法
-
随着类的加载而加载,可以通过"类.静态方法"的方式进行调用;
-
静态方法中,只能调用静态的方法或属性;
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性;
-
在静态的方法内,不能使用this关键字、super关键字;
-
关于静态属性和静态方法的使用,从生命周期的角度去理解。
九、单例模式
1.设计模式的说明
设计模式是在大量的实践中总结和理论化之后优的代码结构、编程风格、以及解决问题的思考方式。
- 常用设计模式 — 23种经典的设计模式 GOF
- 创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
- 创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
2.单例模式要解决的问题
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
3.饿汉式
class Bank{
//1.私化类的构造器
private Bank(){
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank instance = new Bank();
//3.提供公共的静态的方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
4.懒汉式(1)
class Order{
//1.私化类的构造器
private Order(){
}
//2.声明当前类对象,没初始化
//4.此对象也必须声明为static的
private static Order instance = null;
//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
if(instance == null){
instance = new Order();
}
return instance;
}
}
懒汉式(2)
class Order{
//1.私化类的构造器
private Order(){
}
//2.声明当前类对象,没初始化
//4.此对象也必须声明为static的
private static Order instance = null;
static{
instance = new Order();
}
//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
return instance;
}
}
4.两种模式对比
- 饿汉式
- 好处:饿汉式是线程安全的
- 坏处:对象加载时间过长。
- 懒汉式
- 好处:延迟对象的创建。
- 目前的写法坏处:线程不安全。待修改
十、main方法的再理解
-
main()方法作为程序的入口
-
main()方法也是一个普通的静态方法
-
main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)
如何将控制台获取的数据传给形参:String[] args?
运行时:java 类名 “Tom” “Jerry” “123” “true”sysout(args[0]);//“Tom”
sysout(args[3]);//“true”(输出的为字符串类型的true) -->Boolean.parseBoolean(args[3]);
sysout(args[4]);//报异常 -
小结:一叶知秋
public static void main(String[] args){//方法体}权限修饰符:private 缺省 protected pubilc ---->封装性
修饰符:static \ final \ abstract \native 可以用来修饰方法
返回值类型: 无返回值 / 有返回值 -->return
方法名:需要满足标识符命名的规则、规范;“见名知意”
形参列表:重载 vs 重写;参数的值传递机制;体现对象的多态性
方法体:来体现方法的功能
十一、代码块(初始化块)
1.代码块是用来初始化类、对象的信息的
2.分为静态代码块和非静态代码块
-
静态代码块
-
内部可以输出语句
随着类的加载而执行,而且只执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构 -
非静态代码块
-
内部可以输出语句
随着对象的创建而执行
每创建一个对象,就执行一次非静态代码块
作用:可以在创建对象时,对对象的属性等进行初始化
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
3.实例化子类对象时,涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序:
由父及子,静态先行。
4.属性赋值的顺序
-
①默认初始化
-
②显式初始化/⑤在代码块中赋值
-
③构造器中初始化
-
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
-
执行的先后顺序:① - ② / ⑤ - ③ - ④
十一、关键字final
1.可以用来修饰:类、方法、变量
2.具体的:
- 2.1final 用来修饰一个类:此类不能被其他类所继承。
比如:String类、System类、StringBuffer类
-
2.2 final 用来修饰方法:表明此方法不可以被重写
比如:Object类中getClass();
-
2.3 final 用来修饰变量:此时的"变量"就称为是一个常量
final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
static final 用来修饰属性:全局常量
十二、抽象类及抽象方法
1.abstract可以修饰类、方法
2.具体的:
- abstract修饰类:抽象类
- 此类不能实例化
- 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
- 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作 —>抽象的使用前提:继成性
- abstract修饰方法:抽象方法
- 抽象方法只方法的声明,没方法体
- 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
- 子类重写了父类中的所的抽象方法后,此子类方可实例化。
- 若子类没重写父类中的所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
3.注意点:
- 1.abstract不能用来修饰:属性、构造器等结构;
- 2.abstract不能用来修饰私有(private)方法、静态方法、final的方法、final的类;
- 1.静态方法不能被重写
2.如果abstract能修饰静态方法,那么可以直接通过“类.方法”调用,但抽象方法不能被调用。
- 1.静态方法不能被重写
十三、关键字interface
1.使用说明
- 1.接口使用interface来定义
-
2.Java中,接口和类是并列的两个结构
-
3.如何定义接口:定义接口中的成员
-
3.1 JDK7及以前:只能定义全局常量和抽象方法
-
全局常量:public static final的.但是书写时,可以省略不写
-
抽象方法:public abstract的
-
3.2 JDK8以后:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
-
-
- 接口中不能定义构造器的!意味着接口不可以实例化
-
-
Java开发中,接口通过让类去实现(implements)的方式来使用.
-
如果实现类覆盖了接口中的所抽象方法,则此实现类就可以实例化
-
如果实现类没覆盖接口中所的抽象方法,则此实现类仍为一个抽象类
-
-
-
- Java类可以实现多个接口 —>弥补了Java单继承性的局限性
- 格式:class AA extends BB implements CC,DD,EE
- Java类可以实现多个接口 —>弥补了Java单继承性的局限性
-
- 接口与接口之间可以继承,而且可以多继承
-
- 接口的具体使用,体现多态性
-
- 接口,实际上可以看做是一种规范
2.Java8中关于接口的新规范
//知识点1:接口中定义的静态方法,只能通过接口来调用。
//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>类优先原则
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没重写此方法的情况下,报错。–>接口冲突。
//这就需要我们必须在实现类中重写此方法
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
3.面试题:
抽象类和接口的异同?
相同点:不能实例化;都可以包含抽象方法的。
不同点:
1)把抽象类和接口(java7,java8,java9)的定义、内部结构解释说明
2)类:单继承性
接口:多继承
类与接口:多实现
十四、内部类
内部类:类的第五个成员
1.定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.
2.内部类的分类:
成员内部类(静态、非静态 ) vs 局部内部类(方法内、代码块内、构造器内)
3.成员内部类的理解:
一方面,作为外部类的成员:
-
调用外部类的结构
-
可以被static修饰
-
可以被4种不同的权限修饰
另一方面,作为一个类:
-
类内可以定义属性、方法、构造器等
-
可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
-
可以被abstract修饰
4.成员内部类:
4.1如何创建成员内部类的对象?(静态的,非静态的)
//创建静态的Dog内部类的实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
//创建非静态的Bird内部类的实例(非静态的成员内部类):
//Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
4.2如何在成员内部类中调用外部类的结构?
class Person{
String name = "小明";
public void eat(){
}
//非静态成员内部类
class Bird{
String name = "杜鹃";
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
//Person.this.eat();
}
}
}
5.局部内部类的使用:
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
注意点:
在局部内部类的方法中(比如:show如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。
*
jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及之后的版本:可以省略final的声明
总结:
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:成员内部类:外部类
内
部
类
名
.
c
l
a
s
s
局
部
内
部
类
:
外
部
类
内部类名.class 局部内部类:外部类
内部类名.class局部内部类:外部类数字 内部类名.class
十五、异常处理
1.异常
- 异常的体系结构
- java.lang.Throwable
- |-----java.lang.Error:一般不编写针对性的代码进行处理。
- |-----java.lang.Exception:可以进行异常的处理
- |------编译时异常(checked)
- |-----IOException
- |-----FileNotFoundException
- |-----ClassNotFoundException
- |-----IOException
- |------运行时异常(unchecked,RuntimeException)
- |-----NullPointerException
- |-----ArrayIndexOutOfBoundsException
- |-----ClassCastException
- |-----NumberFormatException
- |-----InputMismatchException
- |-----ArithmeticException
- |------编译时异常(checked)
2.[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pf8bpG33-1628525247604)(C:\Users\86198\AppData\Roaming\Typora\typora-user-images\1628523058803.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sve7yNVp-1628525247606)(C:\Users\86198\AppData\Roaming\Typora\typora-user-images\1628523093804.png)]
编译时异常:执行javac.exe命名时,可能出现的异常
运行时异常:执行java.exe命名时,出现的异常
2.异常处理
1.java异常处理的抓抛模型
-
过程一:“抛”:程序在正常执行的过程中,**一旦出现异常,就会在异常代码处生成一个对应异常类的对象。**并将此对象抛出。
一旦抛出对象以后,其后的代码就不再执行。
- 关于异常对象的产生:
- ① 系统自动生成的异常对象
- ② 手动的生成一个异常对象,并抛出(throw)
- 关于异常对象的产生:
-
过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws
2.异常处理方式一:try-catch-finally
try{
* //可能出现异常的代码
*
* }catch(异常类型1 变量名1){
* //处理异常的方式1
* }catch(异常类型2 变量名2){
* //处理异常的方式2
* }catch(异常类型3 变量名3){
* //处理异常的方式3
* }
* ....
* finally{
* //一定会执行的代码
* }
说明:
-
- finally是可选的。
-
- 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
-
- 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没写finally的情况。继续执行其后的代码)
-
-
catch中的异常类型如果没子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
-
-
- 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
-
- 在try结构中声明的变量,再出了try结构以后,就不能再被调用
-
- try-catch-finally结构可以嵌套
3.总结:如何看待代码中的编译时异常和运行时异常?
- 体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
- 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。
4.finally的再说明:
- 1.finally是可选的
- 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
- 3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。
5.异常处理方式二:
"throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!
6.对比两种处理方式
try-catch-finally:真正的将异常给处理掉了。
throws的方式只是将异常抛给了方法的调用者。并没真正将异常处理掉。
7.体会开发中应该如何选择两种处理方式?
- 如果父类中被重写的方法没用throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中异常,必须使用try-catch-finally方式处理。
- 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
3.手动抛出异常
1.在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类的对象。
2.[面试题]
throw 和 throws区别:
throw 表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。
throws 属于异常处理的一种方式,声明在方法的声明处。
3.典型例题
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
// throw new Exception("您输入的数据非法!");
throw new MyException("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
4.自定义异常类
1.如何自定义一个异常类?
-
- 继承于现的异常结构:RuntimeException 、Exception
-
- 提供全局常量:serialVersionUID
-
- 提供重载的构造器
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}
3.手动抛出异常
1.在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类的对象。
2.[面试题]
throw 和 throws区别:
throw 表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。
throws 属于异常处理的一种方式,声明在方法的声明处。
3.典型例题
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
// throw new Exception("您输入的数据非法!");
throw new MyException("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
4.自定义异常类
1.如何自定义一个异常类?
-
- 继承于现的异常结构:RuntimeException 、Exception
-
- 提供全局常量:serialVersionUID
-
- 提供重载的构造器
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}