- 第4章 面向对象(下)
- 4.1 类的继承
- 4.1.1 继承的概念:
- 4.1.2 方法的重写
- 4.1.3 super关键字
- 4.2 final关键字
- 4.3 抽象类与接口
- 4.3.1 抽象方法 :
- 4.3.2 接口:
- 4.4 多态
- 4.4.1 多态的两种主要形式:
- 4.4.2 对象类型的转换
- 4.4.3 instanceof 关键字**
- 4.5 Object类
- 4.6 内部类
- 4.6.1 成员内部类
- 4.6.2 局部内部类
- 4.6.3 静态内部类
- 4.6.4 匿名内部类
- 4.7 异常
- 4.7.1 异常概述
- 4.7.2 try...catch 和 finally
- 4.7.3 throws关键字
- 4.7.4 运行时异常与编译时异常:
- 4.7.5 自定义异常
在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系
定义:在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类。子类继承父类的属性和方法,使得子类对象(实例)具有父类的特征和行为。
extends关键字:
class 父类{
……
}
class 子类 extends 父类{
……
}
继承实例:
1 // 定义Animal类
2 class Animal {
3 private String name; // 定义name属性
4 private int age; // 定义name属性
5 public String getName() {
6 return name;
7 }
8 public void setName(String name) {
9 this.name = name;
10 }
11 public int getAge() {
12 return age;
13 }
14 public void setAge(int age) {
15 this.age = age;
16 }
17 }
18 // 定义Dog类继承Animal类
19class Dog extends Animal {
20 private String color; // 定义name属性
21 public String getColor() {
22 return color;
23 }
24 public void setColor(String color) {
25 this.color = color;
26 }
27 }
28 // 定义测试类
29 public class Example02 {
30 public static void main(String[] args) {
31 Dog dog = new Dog(); // 创建一个Dog类的实例对象
32 dog.setName("牧羊犬"); // 此时访问的方法时父类中的,子类中并没有定义
33 dog.setAge(3); // 此时访问的方法时父类中的,子类中并没有定义
34 dog.setColor("黑色");
35 System.out.println("名称:"+dog.getName()+",年龄:"+dog.getAge()+",
36 颜色:"+dog.getColor());
37 }
38 }
继承中需要注意的要点:
4.1.2 方法的重写(1)在Java中,类只支持单继承,不允许多重继承。也就是说一个类只能有一个直接父类,例如下面这种情况是不合法的
(2)多个类可以继承一个父类
(3)在Java中,多层继承也是可以的,即一个类的父类可以再继承另外的父类。例如,C类继承自B类,而B类又可以继承自A类,这时,C类也可称作A类的子类。例如下面这种情况是允许的
(4)在Java中,子类和父类是一种相对概念,一个类可以是某个类的父类,也可以是另一个类的子类
解释说明:在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写
方法的重写实例:
1 // 定义Animal类
2 class Animal {
3 //定义动物叫的方法
4 void shout() {
5 System.out.println("动物发出叫声");
6 }
7 }
8 // 定义Dog类继承动物类
9 class Dog extends Animal {
10 //重写父类Animal中的shout()方法
11 void shout() {
12 System.out.println("汪汪汪……");
13 }
14 }
15 // 定义测试类
16 public class Example03 {
17 public static void main(String[] args) {
18 Dog dog = new Dog(); // 创建Dog类的实例对象
19 dog.shout(); // 调用dog重写的shout()方法
20 }
21 }
4.1.3 super关键字注意:在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型,且在子类重写的方法不能拥有比父类方法更加严格的访问权限
解释说明:当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,Java提供了super关键字,super关键字可以在子类中调用父类的普通属性、方法以及构造方
super关键字的主要用法:
(1)使用super关键字访问父类成员变量和方法:
语法:super.成员变量
super.成员方法(参数1,参数2…)
使用实例:
1 // 定义Animal类
2 class Animal {
3 String name = "牧羊犬";
4 //定义动物叫的方法
5 void shout() {
6 System.out.println("动物发出叫声");
7 }
8 }
9 // 定义Dog类继承动物类
10 class Dog extends Animal {
11 //重写父类Animal中的shout()方法,扩大了访问权限
12 public void shout() {
13 super.shout(); //调用父类中的shout()方法
14 System.out.println("汪汪汪……");
15 }
16 public void printName(){
17 System.out.println("名字:"+super.name); //调用父类中的name属性
18 }
19 }
20 // 定义测试类
21 public class Example05 {
22 public static void main(String[] args) {
23 Dog dog = new Dog(); // 创建Dog类的实例对象
24 dog.shout(); // 调用dog重写的shout()方法
25 dog.printName(); // 调用Dog类中的printName()方法
26 }
27 }
注意extends的书写位置
(2)使用super关键字方法父类中指定的构造方法
语法:super(参数1,参数2…)
1 // 定义Animal类
2 class Animal {
3 private String name;
4 private int age;
5 public Animal(String name, int age) {
6 this.name = name;
7 this.age = age;
8 }
9 public String getName() {
10 return name;
11 }
12 public void setName(String name) {
13 this.name = name;
14 }
15 public int getAge() {
16 return age;
17 }
18 public void setAge(int age) {
19 this.age = age;
20 }
21 public String info() {
22 return "名称:"+this.getName()+",年龄: "+this.getAge();
23 }
24 }
25 // 定义Dog类继承动物类
26 class Dog extends Animal {
27 private String color;
28 public Dog(String name, int age, String color) {
29 super(name, age);
30 this.setColor(color);
31 }
32 public String getColor() {
33 return color;
34 }
35 public void setColor(String color) {
36 this.color = color;
37 }
38 //重写父类的info()方法
39 public String info() {
40 return super.info()+",颜色:"+this.getColor(); //扩充父类中的方法
41 }
42 }
43 // 定义测试类
44 public class Example06 {
45 public static void main(String[] args) {
46 Dog dog = new Dog("牧羊犬",3,"黑色"); // 创建Dog类的实例对象
47 System.out.println(dog.info());
48 }
49 }
使用super(name,age);
继承了父类中的 this.name=name; 和 this.age=age;
并且可以在super();语句之后添加拓展的构造语句
4.2 final关键字注意:通过super()调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次
可以使用final关键字声明类、属性、方法,在声明时需要注意以下几点:
(1)使用final修饰的类不能有子类
(2)使用final修饰的方法不能被子类重写
(3)使用final修饰的变量(成员变量和局部变量)是常量,常量不可修改
final关键字是一种限制和修饰,可以让一个类不能有子类,且如果父类的方法被final关键字修饰,那么它就不能再被子类重写该方法,被其修饰的变量称为常量,其值不能再发生改变
注意final关键字的书写位置
注意:在使用final声明变量时,要求全部的字母大写。如果一个程序中的变量使用public static final声明,则此变量将成为全局变量,如下面代码所示。
public static final String NAME = "哈士奇";4.3 抽象类与接口
4.3.1 抽象方法 :**解释说明:**当定义一个类时,常常需要定义一些成员方法描述类的行为特征,但有时这些方法的实现方式是无法确定的
抽象方法用abstract关键字修饰的方法,抽象方法在定义时不需要实现方法体
语法:abstract void 方法名称(参数);
注意:当一个类包含了抽象方法,该类必须是抽象类。抽象类和抽象方法一样,必须使用abstract关键字进行修饰
abstract class 抽象类名称{
访问权限 返回值类型 方法名称(参数){
return [返回值];
}
访问权限 abstract 返回值类型 抽象方法名称(参数); //抽象方法,无方法体
}
抽象类的定义规则如下:
(1)包含一个以上抽象方法的类必须是抽象类。
(2)抽象类和抽象方法都要使用abstract关键字声明。
(3)抽象方法只需声明而不需要实现。
(4)如果一个类继承了抽象类,那么该子类必须实现抽象类中的全部抽象方法。
4.3.2 接口:使用abstract关键字修饰的抽象方法不能使用private修饰,因为抽象方法必须被子类实现,如果使用了private声明,则子类无法实现该方法
如果一个抽象类的所有方法都是抽象的,则可以将这个类定义接口。接口是Java中最重要的概念之一,接口(并不是一个独立的东西)是一种特殊的类,由全局常量和公共的抽象方法组成,不能包含普通方法
JDK 8对接口进行了重新定义,接口中除了抽象方法外,还可以有默认方法和静态方法(也叫类方法),默认方法使用default修饰,静态方法使用static修饰,且这两种方法都允许有方法体
接口的声明:使用interface关键字声明
public interface 接口名 extends 接口1,接口2... {
public static final 数据类型 常量名 = 常量值;
//静态方法
public default 返回值类型 抽象方法名(参数列表);
//抽象方法
public abstract 返回值类型 方法名(参数列表){
//默认方法的方法体
}
public abstract 返回值类型方法名(参数列表){
//类方法的方法体
}
}
注意: 接口中的变量默认使用“public static final”进行修饰,即全局常量。接口中定义的方法默认使用“public abstract”进行修饰,即抽象方法。如果接口声明为public,则接口中的变量和方法全部为public
“extends 接口1,接口2…”表示一个接口可以有多个父接口,父接口之间使用逗号分隔。Java使用接口的目的是为了克服单继承的限制,因为一个类只能有一个父类,而一个接口可以同时继承多个父接口
多学一点:经常看到编写接口中的方法时省略了public ,但是接口中的方法访问权限永远是public。与此类似,在接口中定义常量时,可以省略前面的“public static final”,此时,接口会默认为常量添加“public static final”
接口的使用: 接口的使用必须通过子类,子类通过implements关键字实现接口,并且子类必须实现接口中的所有抽象方法。需要注意的是,一个类可以同时实现多个接口,多个接口之间需要使用英文逗号(,)分隔
修饰符 class 类名 implements 接口1,接口2,...{
...
}
接口实例:
//定义抽象类Animal(注意这里声明时忽略了public)
interface Animal{
int ID = 1;
String NAME = "牧羊犬";
void shout();
static int getID(){
return ID;
}
public void info();
//上面有两个抽象方法不用设置函数体
}
interface Action{
public void eat();
}
//定义Dog类实现Animal接口和Action接口
class Dog implements Animal,Action{
//Animal接口里eat方法的重写
public void eat(){
System.out.println("骨头");
}
//Action接口里shout方法的重写
public void shout(){
System.out.println("汪汪汪");
}
//Animal接口里info方法的重写
public void info(){
System.out.println("名称"+NAME);
}
}
//定义测试类
class Example11{
public ststic void main(String args[]){
Systrm.out.println("编号"+Animal.getID());
//接口中的静态方法 getID(); 则可以直接使用接口名调用
Dog dog = new Dog();
dog.info();
dog.shout();
dog.eat();
}
}
注意:接口的实现类,必须实现接口中的所有方法,否则程序编译报错!
如果在开发中一个子类既要实现接口又要继承抽象类,则可以按照以下格式定义子类:
修饰符class 类名 extends 父类名implements 接口1,接口2,... {
...
}
【案例4-1】打印不同的图形
【案例4-2】饲养员喂养动物
【案例4-3】多彩的声音
【案例4-4】学生和老师
【案例4-5】图形的面积与周长计算程序
【案例4-6】研究生薪资管理
4.4 多态4.4.1 多态的两种主要形式:多态概述:多态性是面向对象思想中的一个非常重要的概念,在Java中,多态是指不同对象在调用同一个方法时表现出的多种不同行为,在同一个方法中,这种由于参数类型不同而导致执行效果不同的现象就是多态
(1)方法的重载 (2)对象的多态性–方法重写
4.4.2 对象类型的转换:(1)向上转型:子类对象->父类对象 (2)向下转型->子类对象
转换格式:
- 对象向上转型: 父类类型 父类对象 = 子类实例;
- 对象向下转型:
父类类型 父类对象 = 子类实例;
子类类型 子类对象 = (子类)父类对象;
向上转型实例:
//定义Animal类
class Animal{
public void shout(){
System.out.println("喵喵...");
}
}
//定义Dog类
class Dog extends Animal{
//方法shout的重写
public void shout(){
System.out.println("汪汪...");
}
}
//定义测试类
public class Example15{
public static void main(String args[]){
Dog dog = new Dog();//创建了dog对象
Animal an = dog;//将dog向上转型为Animal类型的对象an
an.shout();//使用父类对象an调用了shout();方法,但实际上调用的是被重写过的shout();方法
}
}
如果对象发生了向上转型关系后,所调用的方法一定是被子类重写过的方法
父类Animal的对象an是无法调用Dog类中的eat()方法的,因为eat()方法只在子类中定义,而没有在父类中定义
向下转型实例:
//定义类Animal
class Animal{
public void shout(){
System.out.println("喵喵...");
}
}
//定义Dog类
class Dog extends Animal{
//方法shout的重写
public void shout(){
System.out.println("汪汪...");
}
public void eat(){
System.out.println("吃骨头");
}
}
//定义测试类
public class Example16{
public static void main(String args[]){
Animal an = new Dog();//此时发生了向上转型,将Dog类的实例转换成了Animal类的实例an
//Animal an = new Dog();
//是Dog dog = new Dog(); Animal an = dog; 的简写形式
Dog dog = (Dog)an;//此时发生了向下转型,将Animal类的实例an转换为Dog类的实例dog
dog.shout();
dog.eat();
}
}
4.4.3 instanceof 关键字**在向下转型时,不能直接将父类实例强制转换为子类实例,否则程序会报错
Java中可以使用instanceof关键字判断一个对象是否是某个类(或接口)的实例
语法 : 对象 instanceof类(或接口)
在上述格式中,如果对象是指定的类的实例对象,则返回true,否则返回false
【案例4-8】模拟物流快递系统
4.5 Object类Object概述:Java提供了一个Object类,它是所有类的父类,每个类都直接或间接继承Object类,因此Object类通常被称之为超类。当定义一个类时,如果没有使用extends关键字为这个类显式地指定父类,那么该类会默认继承Object类
| 方法名称 | 方法说明 |
|---|---|
| boolean equals() | 判断两个对象是否“相等” |
| int hashCode() | 返回对象的哈希码值 |
| String toString() | 返回对象的字符串表示形式 |
在实际开发中,通常希望对象的toString()方法返回的不仅仅是基本信息,而是对象特有的信息,这时可以重写Object类的toString()方法
toString(); 方法实例:
1 // 定义Animal类
2 class Animal {
3 //重写Object类的toString()方法
4 public String toString(){
5 return "这是一个动物。";
6 }
7 }
8 // 定义测试类
9 public class Example19 {
10 public static void main(String[] args) {
11 Animal animal = new Animal(); // 创建Animal类对象
12 System.out.println(animal.toString()); // 调用toString()方法并打印
13 }
14 }
4.6 内部类
4.6.1 成员内部类内部类概述:在Java中,允许在一个类的内部定义类,这样的类称作内部类,内部类所在的类称作外部类,成员内部类可以访问外部类的所有成员
在实际开发中,根据内部类的位置、修饰符和定义方式的不同,内部类可分为4种,分别是成员内部类、局部内部类、静态内部类、匿名内部类
在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类。成员内部类可以访问外部类的所有成员。
1 class Outer {
2 int m = 0; // 定义类的成员变量
3 // 下面的代码定义了一个成员方法,方法中访问内部类
4 void test1() {
5 System.out.println("外部类成员方法");
6 }
7 // 下面的代码定义了一个成员内部类
8 class Inner {
9 int n = 1;
10 void show1() {
11 // 在成员内部类的方法中访问外部类的成员变量
12 System.out.println("外部成员变量m = " + m);
13 }
14 void show2() {
15 // 在成员内部类的方法中访问外部类的成员变量
16 System.out.println("内部成员方法");
17 }
18 }
19 void test2() {
20 Inner inner = new Inner();
21 System.out.println("内部成员变量n = " + inner.n);
22 inner.show2();
23 }
24 }
25 public class Example20 {
26 public static void main(String[] args) {
27 Outer outer = new Outer();
28 Outer.Inner inner = new outer.new Inner();
29 inner.show1();
30 outer.test2();
31 }
32 }
如果想通过外部类访问内部类,则需要通过外部类创建内部类对象,创建内部类对象的具体语法格式如下:
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
(如上代码块28行代码)
4.6.2 局部内部类局部内部类,也叫作方法内部类,是指定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,有效范围只限于方法内部
局部内部类实例:
class Outer{
int m = 0;
void test1(){
System.out.println("外部类成员方法");
}
void test2(){
class Inner{
int n = 1;
void show(){
//在成员内部类的方法中访问外部类的成员变量
System.out.println("外部成员变量m="+m);
test1();
}
}
Inner inner = new Inner();
System.out.println("局部内部成员变量n="+inner.n);
inner.show();
}
}
public class Examp21{
public static void main(String args[]){
Outer outer = new Outer();
outer.test2();
}
}
4.6.3 静态内部类
所谓静态内部类,就是使用static关键字修饰的成员内部类。与成员内部类相比,在形式上,静态内部类只是在内部类前增加了static关键字
但在功能上,静态内部类只能访问外部类的静态成员,通过外部类访问静态内部类成员时,可以跳过外部类直接访问静态内部类
创建静态内部类对象的基本语法格式如下:
外部类名.静态内部类名 变量名 = new 外部类名().静态内部类名();
静态内部类实例:
class Outer{
static int m = 0;
static class Inner{
int n = 1;
void show(){
System.out.println("外部静态变量m="+m);
//有static关键字修饰的静态内部类只能访问有static修饰的外部类的静态变量
}
}
}
public class Example{
public static void main(String args[]){
Outer.Inner inner = new Outer.Inner();
inner.show();
}
}
4.6.4 匿名内部类
匿名内部类是没有名称的内部类。在Java中调用某个方法时,如果该方法的参数是接口类型,除了可以传入一个接口实现类,还可以使用实现接口的匿名内部类作为参数,在匿名内部类中直接完成方法的实现
创建匿名内部类的基本语法格式如下:
new 父接口(){
//匿名内部类实现部分
}
1 interface Animal{
2 void shout();
3 }
4 public class Example23{
5 public static void main(String[] args){
6 String name = "小花";
7 animalShout(new Animal(){
8 @Override
9 public void shout() {
10 System.out.println(name+"喵喵...");
11 }
12 });
13 }
14 public static void animalShout(Animal an){
15 an.shout();
16 }
17 }
匿名类的编写步骤:
**(1)**在调用animalShout()方法时,在方法的参数位置写上new Animal(){},这相当于创建了一个实例对象,并将对象作为参数传给animalShout()方法。在new Animal()后面有一对大括号,表示创建的对象为Animal的子类实例,该子类是匿名的。具体代码如下所示:
animalShout(new Animal(){});
**(2)**在大括号中编写匿名子类的实现代码,具体如下所示:
animalShout(new Animal() {
public void shout() {
System.out.println(“喵喵……”);
}
});
在程序运行的过程中,也会发生各种非正常状况,例如,程序运行时磁盘空间不足、网络连接中断、被装载的类不存在等。针对这种情况, Java语言引入了异常,以异常类的形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理
算术异常案例:
1 public class Example24 {
2 public static void main(String[] args) {
3 int result = divide(4, 0); // 调用divide()方法
4 System.out.println(result);
5 }
6 //下面的方法实现了两个整数相除
7 public static int divide(int x, int y) {
8 int result = x / y; // 定义一个变量result记录两个数相除的结果
9 return result; // 将结果返回
10 }
11 }
程序发生了算术异常(ArithmeticException),该异常是由于文件4-24中的第3行代码调用divide()方法时传入了参数0,运算时出现了被0除的情况。异常发生后,程序会立即结束,无法继续向下执行。
上述程序产生的ArithmeticException异常只是Java异常类中的一种,Java提供了大量的异常类,这些类都继承自java.lang.Throwable类。
接下来通过一张图展示Throwable类的继承体系
Throwable有两个直接子类Error和Exception,其中,Error代表程序中产生的错误,Exception代表程序中产生的异常。
● Error类称为错误类,它表示Java程序运行时产生的系统内部错误或资源耗尽的错误,这类错误比较严重,仅靠修改程序本身是不能恢复执行的。举一个生活中的例子,在盖楼的过程中因偷工减料,导致大楼坍塌,这就相当于一个Error。例如,使用java命令去运行一个不存在的类就会出现Error错误。
● Exception类称为异常类,它表示程序本身可以处理的错误,在Java程序中进行的异常处理,都是针对Exception类及其子类的。在Exception类的众多子类中有一个特殊的子类—RuntimeException类,RuntimeException类及其子类用于表示运行时异常。 Exception类的其他子类都用于表示编译时异常。
Throwable类中的常用方法如下表
| 方法声明 | 功能描述 |
|---|---|
| String getMessage() | 返回异常的消息字符串 |
| String toString() | 返回异常的简单信息描述 |
| void printStackTrace() | 获取异常类名和异常信息,以及异常出现在程序中的位置,把信息输出在控制台。 |
为了解决异常,Java提供了对异常进行处理的方式一一异常捕获。异常捕获使用try…catch语句实现,try…catch具体语法格式如下
try{
//程序代码块
}catch(ExceptionType(Exception类及其子类) e){
//对ExceptionType的处理
}
finally关键字:在程序中,有时候会希望有些语句无论程序是否发生异常都要执行,这时就可以在try…catch语句后,加一个finally代码块
1 public class Example26 {
2 public static void main(String[] args) {
3 //下面的代码定义了一个try…catch…finally语句用于捕获异常
4 try {
5 int result = divide(4, 0); //调用divide()方法
6 System.out.println(result);
7 } catch (Exception e) { //对捕获到的异常进行处理
8 System.out.println("捕获的异常信息为:" + e.getMessage());
9 return; //用于结束当前语句,程序第13行代码就不会执行了,而finally代码块中的代码仍会执行,不受return语句影响
10 } finally {
11 System.out.println("进入finally代码块");
12 }
13 System.out.println("程序继续向下执行…");
14 }
15 //下面的方法实现了两个整数相除
16 public static int divide(int x, int y) {
17 int result = x / y; //定义一个变量result记录两个数相除的结果
18 return result; //将结果返回
19 }
20 }
4.7.3 throws关键字finally中的代码块在一种情况下是不会执行的,那就是在try…catch中执行了System.exit(0)语句。System.exit(0)表示退出当前的Java虚拟机,Java虚拟机停止了,任何代码都不能再执行了
在实际开发中,大部分情况下我们会调用别人编写方法,并不知道别人编写的方法是否会发生异常。针对这种情况,Java允许在方法的后面使用throws关键字对外声明该方法有可能发生的异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过
throws关键字声明抛出异常的语法格式如下:
修饰符 返回值类型 方法名(参数1,参数2…)throws 异常类1, 异常类2…{
//方法体…
}
从上述语法格式中可以看出,throws关键字需要写在方法声明的后面,throws后面需要声明方法中发生异常的类型
throws关键字实例:
1 public class Example28 {
2 public static void main(String[] args) {
3 //下面的代码定义了一个try…catch语句用于捕获异常
4 try {
5 int result = divide(4, 2); //调用divide()方法
7 System.out.println(result);
8 } catch (Exception e) { //对捕获到的异常进行处理
9 e.printStackTrace(); //打印捕获的异常信息
10 }
11 }
12 //下面的方法实现了两个整数相除,并使用throws关键字声明抛出异常
13 public static int divide(int x, int y) throws Exception {
14 int result = x / y; //定义一个变量result记录两个数相除的结果
15 return result; //将结果返回
16 }
17 }
4.7.4 运行时异常与编译时异常:(1)由于使用了try…catch对divide()方法进行了异常处理,因此程序可以编译通过
(2)如果没有使用try…catch对divide()方法进行异常处理,在main()方法继续使用throws关键字将Exception抛出,程序虽然可以通过编译,但从运行结果可以看出,在运行时期由于没有对“/by zero”的异常进行处理,最终导致程序终止运行
参考图
- 编译时异常:
在Exception类中,除了RuntimeException类及其子类,Exception的其他子类都是编译时异常。编译时异常的特点是Java编译器会对异常进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。
处理编译时期的异常有两种方式,具体如下:
(1)使用try…catch语句对异常进行捕获处理。
(2)使用throws关键字声明抛出异常,调用者对异常进行处理。
- 运行时异常:
RuntimeException类及其子类都是运行时异常。运行时异常的特点是Java编译器不会对异常进行检查。也就是说,当程序中出现这类异常时,即使没有使用try…catch语句捕获或使用throws关键字声明抛出,程序也能编译通过。运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复
4.7.5 自定义异常JDK中定义了大量的异常类,虽然这些异常类可以描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况
例如,前面讲解的程序中的divide()方法,不允许被除数为负数。为了解决这个问题,Java允许用户自定义异常,但自定义的异常类必须继承自Exception或其子类
自定义异常:
//自定义一个异常类,这个异常类继承于Exception
public class DivideMinusException extends Exception{
public DivideByMinusException(){
super(); // 调用Exception无参的构造方法
}
public DivideByMinusException(String message){
super(massage); // 调用Exception有参的构造方法
}
}
在实际开发中,如果没有特殊的要求,自定义的异常类只需继承Exception类,在构造方法中使用super()语句调用Exception的构造方法即可。
自定义异常类中使用throw关键字在方法中声明异常的实例对象,格式如下:
throw Exception异常对象
用throw关键字抛出异常对象时,需要使用try…catch语句对抛出的异常进行处理,或者在divide()方法上使用throws关键字声明抛出异常,由该方法的调用者负责处理
自定义异常实例:
public class Example{
public static void main(String args[]){
//定义一个try...catch语句用于捕获异常
try{
int result = devide(4,-2);
System.out.println(result);
}
catch(DivideNyMinusException e){ //对捕获到的异常进行处理
System.out.println(e.getMessage); //打印捕获的异常信息
}
}
public static int divide(int x,int y) throw DivideByMinusException{
if(y<0){
throw new DivideByMinusException("除非是负数"); //捕捉到异常后的行为
}
int result = x/y;
return result;
}
}



