abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。
抽象类:
所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类是是用来捕捉子类的通用特性的,是一种模板,它不能被实例化,只能被用作子类的超类。抽象类必须在类前用abstract关键字修饰。抽象类不能实例
只要包含一个抽象方法的类,该类必须要定义成抽象类
抽象类的目的:
1, 抽象类就是为了继承而存在的,为子类提供一个公共的类型;
2, 封装子类中的重复内容(成员变量和方法);
3, 定义抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。
抽象类中包含抽象方法,抽象方法的声明格式为:
public abstract void cry();
抽象方法是一种特殊的方法:它只有声明,而没有具体的实现
抽象类例子:
public abstract class Animal {
public abstract void cry();
}
子类继承例子:
public class Dog extends Animal{
@Override
public void cry() {
System.out.println("狗叫...");
}
}
抽象类中不只有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:
1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2)抽象类不能用来创建对象(不能被实例);因为抽象类中含有无具体实现的方法
3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。(抽象类可以继承抽象类)
接口(interface):
接口泛指供别人调用的方法或者函数,它是对行为的抽象。接口是抽象的抽象。
接口是抽象方法的集合,是一种形式,一种标准,就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口中的方法必须都是抽象方法,并且接口中所有的方法不能有具体的实现,接口中成员变量只能是public static final这种形式,相当于常量,不可以修改的(一般不在接口中定义成员变量)
方法只能为public,当然你可以显示的声明为protected、private,但是编译会出错
注意点:实现类必须要实现该接口的所有方法
接口的使用,需要使用implements关键字,具体格式如下:
class ClassName implementsInterface1,Interface2,[....]{
}
接口的例子:
interface Door{
void open ();
void close();
}
子类中实现接口:
Public class BigDoor implements Door {
void open (){
//实现
};
void close(){
//实现
};
}
抽象类与接口的区别:
一、语法层面上的区别:
1. 抽象类可以多种修饰方法,接口中只能存在public abstract 方法
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() {
//....
}
}
两者正确使用方式:
宏观上讲:
抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么,具备什么。
抽象类使用:比如,男人,女人,这两个类,他们的抽象类是人。说明,他们都是人。
接口使用:比如,人可以吃东西,猫也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它.
当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。
具体注意点:
1、如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
2、如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
3、如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
ISP(Interface Segregation Principle)接口隔离原则(面向对象的一个核心原则):
1、 它表明使用多个专门的接口比使用单一的总接口要好。
2、 一个类对另外一个类的依赖性应当是建立在最小的接口上的。
3、 一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
总结:
1、一个类只能继承一个抽象类,但是可以实现多个接口。
2、 在抽象类中可以拥有自己的成员变量和非抽象类方法,但是接口中只能存在静态的不可变的成员数据(不过一般都不在接口中定义成员数据),而且它的所有方法都是抽象的。
接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的
3、抽象类和接口所反映的设计理念是不同的,抽象类所代表的是“is-a”的关系,而接口所代表的是“has-a”的关系。
4、实现接口的一定要实现接口里定义的所有方法,而实现抽象类可以有选择地重写需要用到的方法,一般的应用里,最顶级的是接口,然后是抽象类实现接口,最后才到具体类实现。
网友评论