文章目录
前言(转载请说明作者!)4.9~4.16编写
接口
概念
我们知道一个类只能继承一个父类,而在现实中,一个类可能有多个父类继承,假如一个孩子即遗传爸爸,又遗传妈妈。
接口由若干常量定义和一组抽象方法组成,接口中不包括变量和有具体实现的方法。从本质上讲,接口是一种特殊的抽象类,它比抽象类还要抽象,因为它只能包含常量和方法的声明,而没有变量和方法的实现。接口中的方法是由它的实现类来实现。也可以将接口理解为一种契约,主要用于声明一组应该履行的方法。
定义
接口是由常量和抽象方法两部分组成,定义一个接口和创建一个类非常相似。接口定义包括接口声明和接口体。
格式:
[public] interface接口名[extends 父接口名列表]{
//接口体包括常量声明和方法声明
//常量声明
[public] [static] [final] 数据类型常量名=常量值;
//抽象方法声明
[public] [abstract]返回类型方法名(参数列表);
interface是定义接口的关键字,接口名用于指定接口的名称,接口名必须是合法的Java标识符。一般情况下 ,要求首字母大写。
interface关键字前面的public为可选值,用于指定接口的访问权限。如果省略则使用默认的访问权限,只能被同一个包中的其他类和接口使用。
接口也可以被继承,它将继承父接口的所有属性和方法。使用extends关键字可以继承父接口。需要注意的是: 一个接口可以继承多个父接口,它们之间用“,(英文逗号)”分割,形成父接口列表。
接口中的变量都是具有public、static和final修饰符的常量 ,这些修饰符都可以省略,效果一样。
接口中的方法都是public和abstract修饰的方法,这些修饰符也可以省略。
举例
public interface CalInterface {
float PI=3.14159f;//定义用于表示圆周率的常量PI ,省略
了public static final修饰符
float getArea(float r);//定义-一个用于计算面积的方法
float getCircumference(float r);//定义-一个用于计算周长的方法
}
实现
接口在定义后,要想使用接口,就需要借助于类来实现该接口。在类中实现接口可以使用关键字implements ,其基本格式如下:
[修饰符]class <类名> [extends父类名] [implements接口列表]{
//类体
}
可选参数,用于指定类的访问权限,可选值为public、abstract和final。
可选参数,用于指定要定义的类继承于哪个父类。
可选参数,用于指定该类实现的是哪些接口。当使用implements关键字时,接口列表为必选参数。当接口列表中存在多个接口名时,各个接口名之间使用逗号分隔。
在类中实现接口时,方法的名字、返回值类型、参数的个数及类型必须与接口中的完全一致,并且必须实现接口中的所有方法。
使用场合
接口的使用场合主要在两个方面, 一个是多重继承,一个是可扩展性。
关于多重继承,在现实生活中个子类拥有多个直接父类的情况并不少见,而在Java中,类与类之间只允许单继承,因此Java引入了接口来实现多重继承。
案例1
爸爸是个中国人,讲汉语,而且会画画;妈妈是个英国人,讲英语,会唱歌。女儿(Lily)继承 了爸爸讲汉语但不会画画,继承了妈妈的讲英语和唱歌。儿子(Tom)没有继承到爸爸的任何特长,只继承了妈妈的全部特长,还有自己的特长打篮球(playBasketball)。通过问题描述,很容易想到他们之间存在着继承关系。但是对于女儿(Lily),不但继承了爸爸(Father)的某些特长,还继承了妈妈( Mother )的全部特长,而Java中的类只允许单继承,不允许多重继承,将爸爸和妈妈都定义成父类显然不能满足我们的要求,这时我们应该考虑定义接口。
那么是把爸爸和妈妈都定义为接口呢还是其中之一定义为类,另外一个定义为接口呢?
Java中引入接口的目的一方面是为了实现多重继承 ,更重要的目的是通过接口能够更好的提高程序的可扩展性和可维护性。
案例2
电脑USB接口可以插鼠标、优盘、USB风扇。之所以能够插这些设备,是因为它们都符合了USB接口规范
电脑识别的是USB接口, USB接口的规范就类似于Java中的接口,能够插入USB接口的MP3、U盘,类似于Java中接口的具体实现,显然它们的内部结构各不相同,但是厂家在制作它们的时候必须要遵循USB接口的规范。
设计模式
适配器设计模式
//定义接口:
interface A {
public void fun1();
public void fun2();
public void fun3();
}
//定义抽象类作为中间的过渡:
abstract class B implements A{
public void fun1() { }
public void fun20 { }
public void fun3() { }
}
//子类通过继承中间抽象类方式就能够根据需要去重写相应的方法
class C extends B{
public void fun10{
System.out.printn("HELLO..");
}
public class OODemo{
public static void main(String argsQ){
//接口的引用指向子类
A = new C();
a.fun1();
}
}
接口→抽象类(过渡)→子类
简单工厂设计模式
eg
public class USBSimulator {
public static void main(String[] args) {
PC pc=new PC();//生产了一台电脑
USB usb= new MP3();//生产了符合USB接口规范的MP3
pc.plugin(usb);//将MP3插入到电脑中
}
假设现在要修改子类,不创建MP3了,而是其他的实现了USB接口的类对象,该怎么办?很显然,需要修改main方法,而它是一个程序的客户端,假设现在有100个地方有创建子类对象的地方,那么修改就变得麻烦了。我们可以抽象出一个工厂类,专门负责生产各种符合USB规范的东东。
class Factory{
public static USB getUSBInstance(){
return new UDisk() ;
}
则USBSimulator类中的代码:
USB usb=new MP3();//生产了符合USB接口规范的MP3
可以修改为:
USB usb= Factory. getUSBInstance();
异常
开发人员都希望编写出的"程序代码没有错误、运行正常,但在实际的程序开发中,往往存在一些外在因素, 如:
- 操作系统出错
- 除数为0
- 写程序的时候,不小心写错关键字
- 用户输入数据出错
- 数组下标越界
- 需要处理的文件不存在等情况
这些情况的发生使程序产生运行错误。如何处理这些错误?把错误交给谁去做处理?程序如何从错误中恢复?
Java中的异常,指不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。
Java如何处理异常
在Java语言中,对于可能出现的异常都需要预先进行处理,以保证程序的有效运行,否则程序就会出错。
在Java语言中,若某个方法抛出异常,既可以在当前方法中进行捕获、然后处理该异常,也可以将该异常向.上抛出,由方法的调用者来处理。
使用try…catch结构捕获异常
在Java中,对容易发生的异常,可以使用try…catch语句结构捕获,在try代码块中编写:可能发生异常的代码,然后在catch代码块中:捕获执行这段代码时,可能发生的异常。try…catch结构的一 般格式如下:
try{
可能产生异常的代码
}catch(异常类异常对象){
异常处理代码
}
catch代码块类似于方法的声明,包括一一个 异常类类型、和该类型的一个实例,异常类必须是Throwable类的子类,用来指定catch语句要捕获的异常,异常类对象可以在catch代码块中被调用,如调用对象的printStackTrace()方法,将异常信息打印显示到指定的对象中去。
多重catch代码块的用法
当程序员明确知道程序可能会引|发多个异常时,可以在try…catch结构中 ,使用多个catch代码块来进行处理。多个catch块结构的一般格式如下:
try{
可能产生异常的代码
}catch(异常类1异常对象1){
异常1处理代码
} catch(异常类2异常对象2){
异常2处理代码
}
...其他的catch语句块
} catch(异常类n异常对象n){
finally子句的用法
如果要求:不管出现什么异常,都要最后输出“欢迎使用本计算程序",该如何实现呢?
Java中的try…catch结构提供了finally子句,能实现这个功能,在try…catch结构中、使用了finally子句后,不管程序中有无异常发生,也不管之前的try…catch结构、是否顺利执行完毕,最终都会执行finally代码块的中代码,这使得一些不管在任何情况下, 都必须执行的步骤被执行,从而保证了程序的健壮性。
使用throws关键字抛出异常
如果某个方法会抛出异常,但不想在当前的这个方法中来处理这个异常,可以将这个异常抛出,在调用这个方法的代码中,捕捉这个异常并进行处理。Java语言中通过关键字throws,声明某个方法可能抛出的多种异常,throws可以同时声明多个异常,各个异常之间用逗号分隔。
使用throw关键字抛出异常
使用try…catch结构与throws关键字,抛出与捕获的都是系统定义的异常;
Java中提供了throw关键字,可以在方法体内部抛出一个异常类对象。
e.g.
public class ChkAeByThrow {
public static void main(String[] args) {
try {
int age = chkAge("-23"); // 调用chkge方法
System.out.printin("字符串的年龄为," + age + "岁");
} catch (Exception ex) { // 捕获throw物出的异常
System.out.println("年龄数据有逻辑惜误! ");
Systen.out.print1n("原因," + ex.getMessge());
}
/*
*将年龄字符串信息转换为整型数据并判断数据是否合法的方法
* @throws Exception 抛出异常
*/
public static int chkAge(String strAge) throws Exception {
int age = Integer.parseInt(strAge); //将字符串转换为整型
if (age<0) ( //如果年龄小于0,抛出一个异常
throw new Exception("年龄不能为负数!");
return age;
}
}
-
在数字格式的字符串数据,转换为整型数据时(如int age =chkAge(“-23A”)😉,抛出NumberFormatException,该类异常由系统抛出并做处理。
-
当年龄age <0时,发生逻辑错误而抛出的Exception异常。
throw和throws有如下几点不同,使用时要特别注意:
- 作用不同: throw用于Java语言环境不能捕捉的异常:如年龄、性别等逻辑错误、由程序员自行产生并抛出,throws用于声明在该方法内抛出了异常;
- 使用的位置不同: throw位于方法体内部,可以作为单独的语句使用,throws必须跟在方法参数列表的后面,不能单独使用;
- 内容不同: throw抛出一个异常对象,而且只能抛出一个,throws后面跟异常类,而且可以跟多个异常类。
使用异常处理语句的注意事项
进行异常处理时,主要使用了try、catch、finally、 throws、 throw等 关键字,在使用它们时,要注意以下几点:
- 对于程序中的异常,必须使用try……catch结构捕获,或通过throws向上抛出异常,否则编译会出错。
- 不能单独的使用try、catch或着finally代码块,否则代码在编译时会出错。
- try代码块后面,可以单独的跟一个到多个catch块,也可以单独的仅跟一个finally块,catch块和finally块可以同时存在,但finally块一定要跟在catch块之后。
- 在try…cath…finally结构中,不论程序是否会抛出异常,finally代码块都会执行。
- try只跟catch代码配合使用时,可以使用多个catch块,来捕获try代码块中、可能发生的多种异常,异常发生后,Java虚拟机、会由上而下的检查当前catch代码块所捕获的异常,是否与try代码中的发生的异常匹配,若匹配,则不再执行其它的catch代码块。
如果多重catch代码块捕获的是同种类型的异常,则捕获子类异常的catch代码块要放在捕获父类异常的catch块代码之前,否则将会在编译时发生编译错误。