对于面向对象编程来说,形象是它的一大特色之一。在 Java 中,能够通过两种模式来体现 OOP 的形象:接口和抽象类。这两者有太多类似的中央,又有太多不同的中央。很多人在初学的时候会认为它们能够随便调换应用,然而理论则不然。明天咱们就一起来学习一下 Java 培训学习中的接口和抽象类。
一、抽象类
在理解抽象类之前,先来理解一下形象办法。形象办法是一种非凡的办法:它只有申明,而没有具体的实现。形象办法的申明格局为:
abstract void fun();
形象办法必须用 abstract 关键字进行润饰。如果一个类含有形象办法,则称这个类为抽象类,抽象类必须在类前用 abstract 关键字润饰。因为抽象类中含有无具体实现的办法,所以不能用抽象类创建对象。
上面要留神一个问题:在《JAVA 编程思维》一书中,将抽象类定义为“蕴含形象办法的类”,然而前面发现如果一个类不蕴含形象办法,只是用 abstract 润饰的话也是抽象类。也就是说抽象类不肯定必须含有形象办法。集体感觉这个属于钻牛角尖的问题吧,因为如果一个抽象类不蕴含任何形象办法,为何还要设计为抽象类?所以暂且记住这个概念吧,不用去深究为什么。
[public] abstract class ClassName {abstract void fun();
}
从这里能够看出,抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创立了这个抽象类,因为你不能用它来做任何事件。对于一个父类,如果它的某个办法在父类中实现进去没有任何意义,必须依据子类的理论需要来进行不同的实现,那么就能够将这个办法申明为 abstract 办法,此时这个类也就成为 abstract 类了。
蕴含形象办法的类称为抽象类,但并不意味着抽象类中只能有形象办法,它和一般类一样,同样能够领有成员变量和一般的成员办法。留神,抽象类和一般类的次要有三点区别:
1、形象办法必须为 public 或者 protected(因为如果为 private,则不能被子类继承,子类便无奈实现该办法),缺省状况下默认为 public。
2、抽象类不能用来创建对象;
3、如果一个类继承于一个抽象类,则子类必须实现父类的形象办法。如果子类没有实现父类的形象办法,则必须将子类也定义为为 abstract 类。在其余方面,抽象类和一般的类并没有区别。
二、接口
接口,英文称作 interface,在软件工程中,接口泛指供他人调用的办法或者函数。从这里,咱们能够领会到 Java 语言设计者的初衷,它是对行为的形象。在 Java 中,定一个接口的模式如下:
[public] interface InterfaceName {}
接口中能够含有 变量和办法。然而要留神,接口中的变量会被隐式地指定为 public static final 变量(并且只能是 public static final 变量,用 private 润饰会报编译谬误),而办法会被隐式地指定为 public abstract 办法且只能是 public abstract 办法(用其余关键字,比方 private、protected、static、final 等润饰会报编译谬误),并且接口中所有的办法不能有具体的实现,也就是说,接口中的办法必须都是形象办法。从这里能够隐约看出接口和抽象类的区别,接口是一种极度形象的类型,它比抽象类更加“形象”,并且个别状况下不在接口中定义变量。
要让一个类遵循某组顺便的接口须要应用 implements 关键字,具体格局如下:
class ClassName implements Interface1,Interface2,[....]{}
能够看出,容许一个类遵循多个特定的接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有办法。对于遵循某个接口的抽象类,能够不实现该接口中的形象办法。
三、抽象类和接口的区别
1. 语法层面上的区别
抽象类能够提供成员办法的实现细节,而接口中只能存在 public abstract 办法;
抽象类中的成员变量能够是各种类型的,而接口中的成员变量只能是 public static final 类型的;
接口中不能含有动态代码块以及静态方法,而抽象类能够有动态代码块和静态方法;一个类只能继承一个抽象类,而一个类却能够实现多个接口。
2. 设计层面上的区别
1)抽象类是对一种事物的形象,即对类形象,而接口是对行为的形象。抽象类是对整个类整体进行形象,包含属性、行为,然而接口却是对类部分(行为)进行形象。举个简略的例子,飞机和鸟是不同类的事物,然而它们都有一个共性,就是都会飞。那么在设计的时候,能够将飞机设计为一个类 Airplane,将鸟设计为一个类 Bird,然而不能将 航行 这个个性也设计为类,因而它只是一个行为个性,并不是对一类事物的形象形容。此时能够将 航行 设计为一个接口 Fly,蕴含办法 fly(),而后 Airplane 和 Bird 别离依据本人的须要实现 Fly 这个接口。而后至于有不同品种的飞机,比方战斗机、民用飞机等间接继承 Airplane 即可,对于鸟也是相似的,不同品种的鸟间接继承 Bird 类即可。从这里能够看出,继承是一个 “ 是不是 ” 的关系,而 接口 实现则是 “ 有没有 ” 的关系。如果一个类继承了某个抽象类,则子类必然是抽象类的品种,而接口实现则是有没有、具备不具备的关系,比方鸟是否能飞(或者是否具备航行这个特点),能航行则能够实现这个接口,不能航行就不实现这个接口。
2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简略例子,大家都用过 ppt 外面的模板,如果用模板 A 设计了 ppt B 和 ppt C,ppt B 和 ppt C 公共的局部就是模板 A 了,如果它们的公共局部须要改变,则只须要改变模板 A 就能够了,不须要从新对 ppt B 和 ppt C 进行改变。而辐射式设计,比方某个电梯都装了某种报警器,一旦要更新报警器,就必须全副更新。也就是说对于抽象类,如果须要增加新的办法,能够间接在抽象类中增加具体的实现,子类能够不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改变。
上面看一个网上流传最宽泛的例子:门和警报的例子:门都有 open() 和 close() 两个动作,此时咱们能够定义通过抽象类和接口来定义这个抽象概念:
abstract class Door {public abstract void open();
public abstract void close();}
或者:
interface Door {public abstract void open();
public abstract void close();}
然而当初如果咱们须要门具备报警 alarm() 的性能,那么该如何实现?上面提供两种思路:
1)将这三个性能都放在抽象类外面,然而这样一来所有继承于这个抽象类的子类都具备了报警性能,然而有的门并不一定具备报警性能;
2)将这三个性能都放在接口外面,须要用到报警性能的类就须要实现这个接口中的 open() 和 close(),兴许这个类基本就不具备 open() 和 close() 这两个性能,比方火灾报警器。
从这里能够看出,Door 的 open()、close() 和 alarm() 基本就属于两个不同领域内的行为,open() 和 close() 属于门自身固有的行为个性,而 alarm() 属于延长的附加行为。因而最好的解决办法是独自将报警设计为一个接口,蕴含 alarm() 行为,Door 设计为独自的一个抽象类,蕴含 open 和 close 两种行为。再设计一个报警门继承 Door 类和实现 Alarm 接口。
interface Alram {void alarm();
}
abstract class Door {void open();
void close();}
class AlarmDoor extends Door implements Alarm {void oepn() {//....}
void close() {//....}
void alarm() {//....}
}
最初再用一个表格的模式来总结一下抽象类和接口的区别: