接口简介
在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。
如果一个抽象类没有字段,所有方法全部都是抽象方法,就可以把该抽象类改写为接口。在Java中,使用interface
可以声明一个接口。
所谓interface
,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract
的。
我们在设计一个软件的代码架构时,我们都希望事先约定好各个功能的接口(即:约定好接口签名和方法),实际开发时我们只需要实现这个接口就能完成具体的功能!后续即使项目变化、功能升级,程序员只需要按照接口约定重新实现一下,就可以达到系统升级和扩展的目的!
编程举例
书接上回,我们在上一篇博客中写到Soby已经利用抽象类学会了所有球类运动的玩法了。再后来,Soby连球都打腻了,开始玩起了游泳。
很显然之前的,适用于球类运动的play()方法肯定是不适合游泳的,但我们希望Soby既会打球也会游泳,所以干脆直接定义一个叫做体育运动Sports的通用接口,里面包含一个通用的体育运动玩法,具体怎么实现先不管:(注意接口是没有实例字段的)
public interface Sports {
void play(); //通用的体育运动玩法
}
有了这个接口约定之后,让所有的Ball、游泳等运动,都来实现这个接口:(三个球的子类代码不做改变)
public class Ball implements Sports {
public void play() { }
}
public class Swim implements Sports {
public void play() {
System.out.println("Swimming.");
}
}
然后玩家Player也面向接口编程,就可以成功运行啦。
public class Player {
public void play(Sports sports) {
sports.play();
}
public static void main(String[] args){
Player Soby = new Player();
Soby.play(new Badminton());
Soby.play(new Volleyball());
Soby.play(new Basketball());
Soby.play(new Swim());
}
}
编程至此,发现从抽象类到接口的变化不大,一个主要原因是这个例子中抽象类的方法实现的实例字段只有{},没有添加别的,所以看起来和接口区别不大。但抽象类与接口的区别远不止于此,下面来介绍一下接口更广泛的应用。
代码扩展
接口不仅可以像上文那样进行代码解耦,还可以利用接口思想对已有的代码进行扩展。
再举个例子,假设Soby有个好朋友fss,他会的运动只有跑步:
public interface Exercise {
void run(); //通用的锻炼方法
}
public class Run implements Exercise {
public void run() {
System.out.println("Runner is Running");
}
}
public class Runner {
public void run(Exercise exercise) {
exercise.run();
}
public static void main(String[] args) {
Runner fss = new Runner(); //实例化跑者
Run run = new Run(); //实例化跑步这项exercise
fss.run(run);
}
}
有一天fss邀请Soby去跑步锻炼,Soby一看fss的代码是用接口编程的,就答应了。接下来就对Soby进行跑步的培训(代码的扩展):
public class Player implements Exercise {
public void play(Sports sports) {
sports.play();
}
//让Player学会跑步
@Override
public void run() {
System.out.println("Player is Running.");
}
}
这时Player类就可以接受Runner类的跑步邀请了:
public class Runner {
public void run(Exercise exercise) {
exercise.run();
}
public static void main(String[] args) {
Run run = new Run(); //实例化跑步这项exercise
Runner fss = new Runner(); //Runner跑步
fss.run(run);
Player Soby = new Player(); //Player跑步
Soby.run();
}
}
可以看到这一改造过程只增加了代码,并没有修改任何已有代码,就完成了代码扩展,nice !
由于一个类可以继承多个接口,所以之后别的类邀请Player类进行其他运动时,仿照前面的步骤进行代码的添加即可。