学习Spring有一段时间了,对java也有了一点了解,最不能理解的就是接口, 即使是写了接口并实现了它,依然无法理解它到底有什么用?看了其他几篇博客,总结了一下自己的理解。

在JAVA编程语言中是一个抽象类型,是抽象方法的集合。一个类通过继承接口的方式,从而来继承接口的抽象方法。

先从一个通俗的解释看起 (原文:C# 接口《通俗解释》


如果你的工作是一个修水管的,一天客户找上你让你帮装水管,但是有个要求,就是客户喜欢管子是三角形的。

你立马买了三角形的水管回来,在墙上弄个三角形的口子,客户付了钱,你很开心今天有了收入,如下图,很好:

但是好景不长,客户过了一个星期又来找,因为他觉得三角形不好看,要让你换成正方形的水管,你不得不换,因为顾客就是上帝。好吧,继续在墙上弄个正方形的口子,然后又换成正方形的管子来接上。好了,如下图:(但是可能觉得为什么一开始不说要正方形的?因为需求总在变化。。。)

你累得满头大汗,但是还是完成了。可惜不久,客户又来找你,因为他想换成椭圆形的管子了。虽然你很无奈,但是你还是不得不花了几个小时完成。如下图:

安装完成,这时你可能在考虑,为什么换不同形状的水管,我都要大动干戈一番呢?于是你想到一个好方法,那就是墙上设计一个固定的水管并且是圆形的,当客户喜欢什么形状的水管,那么我只需要把客户喜欢的水管的一头做成圆形的,这样,以后都不需要去动墙上的水管了。这是一个好办法。就先在墙上弄个圆形的口,这个口就叫做接口。如下图:

如你所见,墙上有个圆形的口,但是按照原本的:

三角形水管两端是三角形
正方形水管两端是正方形
椭圆形水管两端是椭圆形

那是肯定接不上的,因为三角形、正方形、椭圆形的口怎么和墙壁上圆形的口对接呢?

所以先要实现接口,把:

三角形水管一端做成圆形
正方形水管一端做成圆形
椭圆形水管一端做成圆形

如图,所以,圆形接口做出来了,具体实现是客户去安装,接口本身并不会安装其他形状的水管,换句话说就是接口没有具体实现,只是告诉你,你的水管要接入,必须有一端是圆形的(接口的约束),因为我只留这个圆形的接口,你要装别的形状的管子,先把一个弄成圆形的就好了(子类去实现接口的方法),不管什么形状,都要一个必须做成圆形才能对接得上,它必须要你按照我的规范来做。这就是为什么新手会觉得接口什么都不做,只定义接口,没有任何实现,那不是多此一举吗?因为它的实现是子类去完成。这样只要客户喜欢什么形状的水管,只要实现了我的接口(圆形),都能对接得上,而且改变起来也很方便,只要把水管扭上去就行了,不用在去给墙壁挖洞了。


初步了解接口,再用代码进一步理解

需求:公司有两个人分别写了2个动物类,让你写一个类来输出它们各自喜欢的食物。

//A写的Dog类,里面有个likeFood方法
class Dog
{ public void likeFood()
{
Print("我是小狗,我喜欢吃肉");
} }
//B写的Cat类,里面有个likeFood方法,如下:
class Cat
{ public void likeFood()
{
Print("我是小猫,我喜欢吃鱼");
} }

你写的Zoo类如下:

//动物园类
class Zoo { public void show(Dog dog){
dog.likeFood();
} public void show(Cat cat){
cat.likeFood();
} }

在输出的时候使用如下:

void Main()
{
Zoo zoo = new Zoo();
zoo.show(new Dog()); //"我是小狗,我喜欢吃肉"
zoo.show(new Cat()); //"我是小猫,我喜欢吃鱼"
}

这一切工作良好,但好景不长,公司又需要给动物园增加一个猴子,让C去写这个Monkey类,并能输出它喜欢的食物。


class Dog
{ public void likeFood()
{
Console.WriteLine("我是小狗,我喜欢吃肉");
} }
//B写的Cat类,里面有个likeFood方法,如下:
class Cat
{ public void likeFood()
{
Console.WriteLine("我是小猫,我喜欢吃鱼");
} }
//C写的Monkey类,里面有个likeFood方法,如下:
class Monkey
{ public void likeFood()
{
Console.WriteLine("我是猴子,我喜欢吃桃子");
} }

于是你的Zoo类就变成了这样,仅仅多了一个重载方法:

class Zoo
{
public void show(Dog dog)
{
dog.likeFood();
} public void show(Cat cat)
{
cat.likeFood();
} public void show(Monkey money)
{
money.likeFood();
}
} void Main()
{ Zoo zoo = new Zoo();
zoo.show(new Dog()); //"我是小狗,我喜欢吃肉"
zoo.show(new Cat()); //"我是小猫,我喜欢吃鱼"
zoo.show(new Monkey()); //"我是猴子,我喜欢吃桃子" }

虽然只是增加了一个类,但善于思考的你马上就会想到:“如果后面还有更多动物要输出它们喜欢的食物,我的Zoo类都要修改,这对我来说不是一件好事。”
仔细观察Zoo类,发现不变的是show方法,变化的是show方法是参数。因为每个动物都不一样,所以参数也就不一样。所以原来就需要重载多个方法。
如果有一个类,能接收所有动物,那不就解决了?没错,于是你想到了定义一个父类叫Animal,里面有个likeFood方法,让所有动物类去继承Animal。

class Zoo
{ public void show(Animal animal)
{
animal.likeFood();
} } class Animal
{ public void likeFood()
{
Print("我是Animal类");
} }

你告诉原来的A和B两人,让它们写的动物类都去继承Animal,并且里面有个输出动物喜欢食物的方法。

class Dog : Animal
{ public void likeFood()
{
Print("我是小狗,我喜欢吃肉");
} } class Cat : Animal
{ public void likeFood()
{
Print("我是小猫,我喜欢吃鱼");
} } class Monkey : Animal
{ public void likeFood()
{
Print("我是猴子,我喜欢吃桃子");
} }

运行也一切良好,不管你以后还有什么类,只要让需要添加的动物类,继承Animal,并有个likeFood方法,那么你无需修改Zoo,只需要再main方法里传入动物类的实例就能正常工作。
你大赞你聪明绝顶,这样一来,你的Zoo根本不需要改变了。
有一天,公司新来一个人,暂时叫D吧,公司让D写个兔子类,你告诉D,你写的Rabbit类必须继承Animal,并且有一个它喜欢的食物的方法。

class Rabbit : Animal
{ public void favoriteFood()
{
Print("我是兔子,我喜欢吃萝卜");
} } void Main()
{ Zoo zoo = new Zoo();
zoo.show(new Dog()); //"我是小狗,我喜欢吃肉"
zoo.show(new Cat()); //"我是小猫,我喜欢吃鱼"
zoo.show(new Monkey()); //"我是猴子,我喜欢吃桃子"
zoo.show(new Rabbit()); //"我是Animal类" }

Raabit并没有输出预想的结果,你不得不花了点时间去排查原因,最后你发现这不是什么大问题,因为新来的D虽然写了Rabbit类,但是他并不知道你们之前约定的动物喜欢的食物命名为:likeFood()
D写的Rabbit类,里面的方法叫:favoriteFood()
虽然最后D修改他的Rabbit类的方法为likeFood(),但你还是对这个问题做了一番思考,为什么会导致这个问题?
那是因为没有一种约束,使得子类继承父类的时候必须实现父类的方法。有没有一个类,能让它的子类必须实现它定义的方法?有,那就是接口
于是你修改Animal为接口,代码如下:

interface Animal {

    public void likeFood();

}

总结

由上述的例子可以总结接口的几个用处:

  1. 使代码易于维护,不管增加多少动物类,只要实现了animal接口,就都能拿来用
  2. 制定一种标准和规范,减少命名不统一带来的一系列问题
  3. 方便团队开发,设计者不用关心具体方法的实现,实现者可以清楚地知道自己的任务是什么。

这里还有一个问题:在我写代码时,都是先有方法,对象,再有类,然后才去抽象成接口,那么我的每一个类都需要抽象成接口吗?在开发过程中,每写一个方法都要去写它的接口的抽象方法,实现它的serviceTest以及调用它的controllerTest,最后才能真正放到程序中去用,即使是一个小小的功能都要做很多“无用功”,而且需求一旦变更,改起来不是更麻烦?

Java 接口理解的更多相关文章

  1. java接口理解(转载)

    今天和同事好好的讨论了java接口的原理和作用,发现原来自己的对接口的理解仅仅是局限在概念的高度抽象上,觉得好像理解了但是不会变化应用其实和没有理解差不多.以前看一个帖子说学习一个东西不管什么时候都要 ...

  2. 我对面向对象设计的理解——Java接口和Java抽象类

    在没有好好地研习面向对象设计的设计模式之前,我对Java接口和Java抽象类的认识还是很模糊,很不可理解. 刚学Java语言时,就很难理解为什么要有接口这个概念,虽说是可以实现所谓的多继承,可一个只有 ...

  3. Java学习之Java接口回调理解

    Java接口回调 在Java学习中有个比较重要的知识点,就是今天我们要讲的接口回调.接口回调的理解如果解释起来会比较抽象,我一般喜欢用一个或几个经典的例子来帮助加深理解. 举例:老板分派给员工做事,员 ...

  4. java接口的理解

    接口的最主要的作用是达到统一访问,就是在创建对象的时候用接口创建,[接口名] [对象名]=new [实现接口的类],这样你像用哪个类的对象就可以new哪个对象了,不需要改原来的代码,就和你的USB接口 ...

  5. java接口调用——webservice就是一个RPC而已

    很多新手一听到接口就蒙逼,不知道接口是什么!其实接口就是RPC,通过远程访问别的程序提供的方法,然后获得该方法执行的接口,而不需要在本地执行该方法.就是本地方法调用的升级版而已,我明天会上一篇如何通过 ...

  6. Java接口的表现形式

    一.概念理解 Java接口是一些方法特征的集合,并没有方法的具体实现,类似于电源插座,可以充不同类型的电器,但是必须适配特定的接口规范.接口是抽象化的,所以其不能被实例化的(不能有构造函数,创建对象) ...

  7. Java初始化理解与总结 转载

    Java的初始化可以分为两个部分: (a)类的初始化 (b)对象的创建 一.类的初始化 1.1 概念介绍: 一个类(class)要被使用必须经过装载,连接,初始化这样的过程. 在装载阶段,类装载器会把 ...

  8. Effective Java通俗理解(持续更新)

    这篇博客是Java经典书籍<Effective Java(第二版)>的读书笔记,此书共有78条关于编写高质量Java代码的建议,我会试着逐一对其进行更为通俗易懂地讲解,故此篇博客的更新大约 ...

  9. Effective Java通俗理解(下)

    Effective Java通俗理解(上) 第31条:用实例域代替序数 枚举类型有一个ordinal方法,它范围该常量的序数从0开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...

随机推荐

  1. java中数组输出的方式

    方式1:遍历输出 public class Main { public static void main(String[] args) { int[] ns = { 1, 4, 9, 16, 25 } ...

  2. Django(十三)状态保持 —— cookie与session+ajax异步请求+session记住登录状态+cookie记住登录名密码

    一.状态保持的概述 http协议是无状态的.下一次去访问一个页面时并不知道上一次对这个页面做了什么.因此引入了cookie.session两种方式来配合解决此问题. Duplicate entry:重 ...

  3. 创建springboot2.1项目运行报错

    刚创建好一个项目,运行就报错:in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging ...

  4. Golang的基础数据类型-布尔型

    Golang的基础数据类型-布尔型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.bool类型概述 bool类型的取值范围: bool类型的值只有两种,其值不为真即为假,可以用 ...

  5. maven集成SSM项目,Tomcat部署运行——SSM整合框架搭建(二)之问题

    问题一.当放开controller中的方法,出现如下问题 ### Error querying database. Cause: org.springframework.jdbc.CannotGetJ ...

  6. JavaWeb面试题(转)

    1.Tomcat的优化经验 答:去掉对web.xml的监视,把JSP提前编辑成Servlet:有富余物理内存的情况下,加大Tomcat使用的 JVM内存. 2.什么是Servlet? 答:可以从两个方 ...

  7. python 输出99乘法表

    for i in range(1,10): for j in range(1,i+1): print("%s*%s=%2s"%(i,j,i*j),end=" " ...

  8. 解决Exception: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z

    在项目中添加src中添加NativeIO类 /** * Licensed to the Apache Software Foundation (ASF) under one * or more con ...

  9. css快速浏览

    meta <meta charset="utf-8" /> <meta name="keywords" content="key1, ...

  10. Python 中使用 ddt 来进行数据驱动,批量执行用例,修改ddt代码

    1. 什么是数据驱动? 使用数据驱动有什么好处? 用例执行是靠数据来驱动的,每条测试用例除了测试数据不一样意外,所有的用例代码都是一样的,为了使用例批量执行,我们会使用数据驱动的思想来批量执行测试用例 ...