在很多时候发现抽象类可以完全取代接口,那接口存在的意义是什么,学习初期不知道什么场合应该使用抽象类,什么时候应该用接口?
从语法角度很容易发现的它们的不同:
·Java只能单继承,而接口可以间接实现多继承
·抽象类的field可以是静态的,而接口的field只能是静态常量(static final,默认情况下不需要声明)。
·抽象类的方法可以是静态的,但是接口的方法不能是静态的(由于接口的方法都是抽象的,所以没有具体实现,直接调用肯定出错,所以在编译阶段就被禁止了。推理得出抽象类的抽象方法也是不能为静态的,这恰好说明了接口的方式省略了“Abstract” 关键字)。
·抽象类的方法可以是public、default、protected、private,但是接口的方式只能是public的(默认省略)。
·抽象类可以有构造器,其目的是要初始化抽象类,而接口没有构造器。
·抽象类有初始化代码块,但是接口没有初始化代码块。
接口和抽象类的共同点:
·他们都具有抽象的方法,不能被实例化。
·继承抽象类或者实现接口的类(注意不是抽象类)都必须实现这些抽象方法。
其实从语法不难发现接口和抽象类之间的联系,但这些并不是我这篇文章想要表达的,我更想从设计目的和使用场合下对它们进行分析。
接口更像是对抽象的抽象,它体现是的是一种规范,是一系列规则的组合,在不同的模块间制定的接口规定了模块之间耦合的标准,在不同的进程之间,接口规定了进程间通信的标准。
软件开发中,具体的事物总是发生着变化,越是抽象的事物越是不容易变化(比如变化本身),从接口的语法特性上可以看出(相对于抽象类)它只提供了一些最基本的功能给程序员,而将具体实现相关的功能都给屏蔽了(不能有具体实现,不能有静态方法,只允许常量field····),目的是让程序员尽可能抽象出系统架构中固定的部分,写出高质量的代码。而抽象类体现的是一种更小范围的的规范,从语法上可以看出它有一些涉及具体实现的特性,这就注定了抽象类不需要用在一些抽象度较高的场合(比如只需要抽象方法和常量场合)。抽象类是针对具体的抽象,而接口是针对抽象的抽象。
比如Java编写“状态机”的例子(下面的列子是通过状态机的方法实现OTA升级)。
/抽象出一个接口用于处理不同状态下的事务。
interface OTAState
{
//定义每种状态下可能的返回值
int RET_DONE = 0;
int RET_GOON = 1;
int RET_WAIT_DATA = 2;
int RET_BREAK = 3;
//抽象方法:执行各个状态下应该完成的事务
int running(Message message);
}
//实现
class StateStart implements OTAState
{
......
@Override
public int running(Message message) {//实现该状态下应该完成的事务
......
mRunningState = mStateFinish;//切换到下一个状态
return RET_WAIT_DATA;//返回值表示处理结果
}
......
}
class StateFinish implements OTAState{
......
@Override
public int running(Message message) {
......
mRunningState = mStateDone;
return RET_WAIT_DATA;
}
......
}
OTAState mRunningState;
//线程运行时调用run().
public void run() {
......
while(mIsActived){
result = mRunningState.running(null);//无差别的处理不同状态下的的行为
if(result == RET_BREAK || result == RET_DONE){//处理返回值
break;
}
if(result == RET_WAIT_DATA){
mCMDData = WaitAndGetData();
}
}
......
}
如果通过上面的描述你仍然不能确定何时是用接口,何时是用抽象类,那我建议的原则就是,如果在具体实现时抽象类和接口之间可以相互替换,那就优先使用接口。