曾看过很多形象的比喻,比如买电脑回来要有USB接口,不能直接把鼠标焊在主板上之类的,很生动,但是对初学者看完还是一脸“啥?你说啥?这到底和接口有什么用的问题有啥关系?”的表情,所以感觉还是用代码来举例比较好。
以下是我在知乎上看到的一个回答,我个人认为很好理解,又形象生动,又有代码可以参考。
推荐大家看看原答案,评论里有一些童鞋提的问题,一起看下来会有更深的理解。我根据原答案和评论修改了接口、类和方法的名称还有部分描述
- 接口的作用对于很多新手来说很不容易理解,我给大家举个例子。
- 接口只是一个规范,所以里面的方法都是空的。
- 假如我开了一个宠物粮店,声明了一个买东西的动作,这就相当于一个接口,
/**
* Created by wanggs on 2017/7/7.
*/
public interface BuySomeThing {
public abstract void buy();
}
- 当一条狗看到了,自己要买东西,所以它去实现这个接口
/**
* Created by wanggs on 2017/7/7.
*/
public class Dog implements BuySomeThing {
public void buy() {
System.out.println("我是狗,我要买狗粮");
}
}
- 当一只猫看到了,自己要买东西,所以也去实现这个接口
/**
* Created by wanggs on 2017/7/7.
*/
public class Cat implements BuySomeThing {
public void buy() {
System.out.println("我是猫,我要买猫粮");
}
}
- 当狗和猫来我的店之前,我是不知道他们到底是什么,但是当他们来到我的店,我就知道一个要猫粮粮,一个要狗粮粮。因为他们都实现了我这个接口,都可以买。下面这个类相当于一个接待顾客的类,即店小二,他接待所有实现了我这个宠物店接口的动物,传进来一个BuySomeThing类型的宠物,注意,这个BuySomeThing是接口
/**
* Created by wanggs on 2017/7/7.
*/
public class PetShop {
public void sell(BuySomeThing buySomeThing){
buySomeThing.buy();
}
}
- 好了,这个时候我这个老板出现了,我可以给他们卖粮食了,相当于测试类
public class Tests {
public static void main(String[] args) {
BuySomeThing dog = new Dog();//实例化一条狗,相当于把狗顾客实例化
BuySomeThing cat = new Cat();//实例化一只猫,相当于把猫顾客实例化
PetShop petShop = new PetShop();//实例化一个店小二
petShop.Sell(dog);//把狗交给店小二
petShop.Sell(cat);//把猫交给店小二
}
}
- 这样运行的结果就是
我是狗,我要买狗粮
我是猫,我要买猫粮
你知道吗,整个过程我这个店主其实根本不知道来的到底是猫是狗还是其他什么,我只要有一个店小二,把这些来的不知什么动物都全部交给店小二,店小二就知道怎么去卖了,因为这些狗啊猫啊都实现了我这个宠物店的接口,而店小二就负责接待所有实现了我这个接口的动物。这就有一个好处,假如明天来了一头小猪,只要它实现了我这个接口,我只管交给店小二处理就OK了,我这个店小二根本不需要变化,我这个店主也只需要实例化一下这个动物就OK
你想,假如没有接口,会怎么办,来一个猫,我要去创造一个猫,还要实例化,来一只狗,我要创建一只狗,同样要实例化,还要配备专门的店小二去接待,就会相当麻烦
说点自己的感想:小白经常认为的一点是,既然我要重写所有方法,我为什么还要用这个接口呢?我同样也写这些方法,也用这些参数,不用接口行不行?难道接口只是定义了一些非得让我重写不可的方法头?
其实不然,接口经常用在非个人项目上,得合作,不是一个人写所有。所以不能只想到你实现了这个功能,要想到你实现完之后别人会因为你这个类实现了规定好的接口而可以直接用来做下面的工作,比如你实现了buy功能,但是别人不知道啊,但是你实现了BuySomeThing这个接口,别人就知道你肯定实现了buy这个功能,然后可以直接调用(参考PetShop这个类)
另外接口也很好的规范了实现时的方法名参数啥的,避免了漏写一下方法实现,错写一些参数。
最后的最后,我总结一下接口的作用吧:
多态 向上转型体现了多态的思想,本身接口就是面向对象思想里体现出来的一个特性
规范 定下了一个方法名传入参数类型返回值类型的规范,避免了很多不必要的麻烦
协议 双方协议好,只要实现预定好的接口的就能用来实现后续的功能,不关心实现接口的类的具体实现
4.扩展 扩展一个新功能,只要实现预定好的接口,这个新功能就能被调用维护 当改变一个功能的实现甚至换成别的类的时候,但如果还有其他地方引用了原类,很难维护。如果使用接口可以轻易切换成新类的引用
安全 在一个普通类实现接口以后,向上转型,则只暴露出接口描述的方法,别人获得的引用也只能使用接口描述的方法,所以安全,比如回调机制