上一篇讲完了抽象类,这一篇主要讲解比抽象类更加抽象的内容——接口。

  什么是接口呢?先来看一个现实中的栗子,我们常用的插座,一般分为两孔和三孔,所以基本上不管是什么电器,只要插头插进去就可以正常使用,想想看,如果没有这样的规范,有十几种不同的插座孔,每个电器的插头都不一样,还不得崩溃掉。

  先来看个栗子:

/**
* @author Frank
* @create 2017/11/22
* @description 可比较接口,用于实现类对象排序
*/
public interface Isortable {
//a>b则返回正整数,相等则返回0,否则返回负整数
int compareWith(Object a);
}

  这是一个简单的接口,使用interface关键字来定义接口。

  接口是描述可属于任何类或者结构的一组行为,是用于定义程序的一种规范,任何实现了接口的类都必须实现接口的所有方法,体现的是“如果你是。。。就必须能。。。”的思想。

  在接口中,不能有方法的实现,也就是说,里面所有方法都是public abstract的,里面只能由静态变量,不能存在普通成员变量,可谓是抽象的集大成者。那为什么要使用接口呢?

  还是继续我们之前的比喻,任何按照规范进行生产的插头都能获得电力,而不同插座虽然生产工艺不同,质量也不一样,但并不影响电器的正常使用,电器并不会关心插座的内部实现,这样就能屏蔽掉一些底层的细节,只暴露出接口供电器使用。

  对于软件开发而言,按照接口的规范进行调用,就能获得期望的功能,按照接口的规范实现接口的方法,就能提供所期望的功能。接口的意义在于抽象,而抽象可以很好的解耦合。

  我们来回头看看上一篇的栗子,我们从具体的商品类中抽象出了一个商品类,从而实现了代码复用和统一管理,也降低了程序的耦合度,比如一个排序方法,参数设置为Phone类的话,那就只能往里面放Phone类型的对象,而如果设置成Goods类,则Phone、Television、Computer类的对象都可以传入进去,这样就降低了程序的耦合度,也就是相互之间的依赖度。

  而接口则是更高层的抽象,主要是对于行为的抽象,可以把它看作是一组规范或者要求,就好比要开车就要先考驾照,这个驾照就相当于接口,你有了这个驾照,就代表你有开车的能力和资格,因为“如果你要有驾照,你就必须能开车“。这样交警就不会为难你了,你跟交警之间通过驾照这个接口进行交流和沟通,而不是用口才去说服他。想一想,如果没有驾照这种规范,总不能没见到一个开车的人都要先当场测试一下他的能力才能让他上路吧。

  在复杂的系统构架中,往往分成很多层级,上层要使用下层提供的服务,而层级之间是通过接口进行交流的,上层对于下层仅仅是接口的依赖,而不是具体类的依赖,因为只要实现了相应的接口,就可以提供相应的服务,就像只要有教师资格证,就代表你有当老师的资格和本事,关注的不是你这个对象,而是你教书的能力,也就是你能提供的服务。当下层需要改变的时候,只要接口不变,上层可以完全不用改变,甚至可以在上层不知情的情况下完全换掉下层代码,正因为接口的存在,让层级之间的耦合度大大降低。就像你的U盘,如果旧的坏了,直接换上新的U盘就可以插上,即插即用,电脑跟U盘之间通过接口进行交流。

  好了,说了这么多,真是很罗嗦,还是来看代码吧,实践出真知。我们来把上一篇的内容稍做修改,上面的代码定义了一个Isortable接口,用于比较两个对象,以用于之后的排序。

  然后我们定义一个Sort类,用于进行排序,可以使用各种类型的排序,如冒泡排序,选择排序,快速排序,希尔排序,这里简单起见,只用了冒泡排序。

/**
* @author Frank
* @create 2017/11/22
* @description 排序类
*/
public class Sort {
//冒泡排序,从大到小排序
public static void bubbleSort(Isortable[] isortables){
for (int i = 0;i<isortables.length-1;i++){
for(int j = 0;j<isortables.length-i-1;j++){
if(isortables[j].compareWith(isortables[j+1])<0){
//交换两者的值
Isortable tmp = isortables[j+1];
isortables[j+1] = isortables[j];
isortables[j] = tmp;
}
}
}
}
}

  然后在Goods类中实现Isortable接口。使用implements关键字。

/**
* @author Frank
* @create 2017/11/21
* @description
*/
public abstract class Goods implements Isortable{
//定义各个类共有的属性
private String title;
private Double price; //定义构造器
public Goods(String title, Double price) {
this.title = title;
this.price = price;
} //定义设置器和访问器
public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public Double getPrice() {
return price;
} public void setPrice(Double price) {
this.price = price;
} //声明抽象打印方法
abstract void print(); //实现Isortable接口,覆盖compareWith方法
@Override
public int compareWith(Object a) {
//由于还没有说明泛型,所以直接强制转换类型了
Goods g = (Goods)a;
if(this.price > g.getPrice()){
return 1;
}else if(this.price < g.getPrice()){
return -1;
}
return 0;
} }

  由于Goods类实现了Isortable接口,所以继承于Goods类的所有类也都实现了该接口,接下来我们修改一下测试类进行测试。

/**
* @author Frank
* @create 2017/11/21
* @description
*/
public class Test {
public static void main(String[] args) {
Goods[] goodsList = new Goods[3];
goodsList[0] = new Phone("IphoneX",9688.00,5.8,24.0);
goodsList[1] = new Computer("Alienware15C-R2738",17699.00,"i7-7700HQ","GTX1060");
goodsList[2] = new Television("SAMSUNG UA78KU6900JXXZ",21999.00,78.0,"4K"); Sort.bubbleSort(goodsList);
for (Goods g:goodsList)
System.out.println(g.getTitle()+" "+g.getPrice());
}
}

  输出如下:

SAMSUNG UA78KU6900JXXZ 21999.0
Alienware15C-R2738 17699.0
IphoneX 9688.0

  这样就按价格进行了从大到小的排序了,怎么样,接口用起来很简单方便吧,这样以后Goods类不管有多少子类,都可以用Sort的bubbleSort方法进行排序,还可以修改或者增加Sort类的方法,让它按你想要的规则进行排序。

  其实在Java中已经有类似的接口了,Comparable接口和Comparator接口,因为使用了泛型,就不会像这里的代码需要强制类型转换了(而且强制类型转换也有一定风险),而很多方法可以对实现了Comparable接口的类进行排序,这就很棒了。(手动滑稽)

  在实际使用中,往往每个人都会负责不同的模块开发,不同的模块之间通常用接口进行交流,因为如果A程序员开发A1类,需要使用B程序员开发的B1类,若是直接调用B1类,那就只能先等B1类开发好之后才能进行A1类的开发,而且如果B1类有任何改动,很可能需要修改A1类的代码,这样耦合度就很高了,而如果使用接口的话,A1类只需要接受接口类型的参数,就可以直接调用相应的方法,而B1类只需要实现接口即可,B1类即使有改动,只要接口不变,那么它向A1类提供的服务也不会变,这样A1类就不需要进行改变,耦合度就降低了。

  现在小结一下:

  接口是对一组特定行为的抽象,是一种规范,只能有方法签名,而不能有实现,所有的方法默认为abstract,且访问权限只能是public,不能有普通成员变量,可以有静态成员变量,接口可以继承接口,一个类可以实现一个接口,也可以实现多个接口,接口的存在可以降低程序的耦合度,增加程序的灵活性。引用大神的话便是,接口和实现分离,面向接口编程。

  至此,接口讲解完毕,欢迎大家继续关注。

  

  

【Java入门提高篇】Day2 接口的更多相关文章

  1. 【Java入门提高篇】Day1 抽象类

    基础部分内容差不多讲解完了,今天开始进入Java提高篇部分,这部分内容会比之前的内容复杂很多,希望大家做好心理准备,看不懂的部分可以多看两遍,仍不理解的部分那一定是我讲的不够生动,记得留言提醒我. 好 ...

  2. 【Java入门提高篇】Day20 Java容器类详解(三)List接口

    今天要说的是Collection族长下的三名大将之一,List,Set,Queue中的List,它们都继承自Collection接口,所以Collection接口的所有操作,它们自然也是有的. Lis ...

  3. 【Java入门提高篇】Day19 Java容器类详解(二)Map接口

    上一篇里介绍了容器家族里的大族长——Collection接口,今天来看看容器家族里的二族长——Map接口. Map也是容器家族的一个大分支,但里面的元素都是以键值对(key-value)的形式存放的, ...

  4. 【Java入门提高篇】Day3 抽象类与接口的比较

    抽象类跟接口都讲完了,现在来做一个比较. 其实说实话,没有多大的可比较性,它们是完全不同的两个东西,它们的抽象不在同一个层级上.但是为了让大家更好的理解,还是做一个比较吧,毕竟它们都很抽象(233). ...

  5. 【Java入门提高篇】Day14 Java中的泛型初探

    泛型是一个很有意思也很重要的概念,本篇将简单介绍Java中的泛型特性,主要从以下角度讲解: 1.什么是泛型. 2.如何使用泛型. 3.泛型的好处. 1.什么是泛型? 泛型,字面意思便是参数化类型,平时 ...

  6. 【Java入门提高篇】Day21 Java容器类详解(四)ArrayList源码分析

    今天要介绍的是List接口中最常用的实现类——ArrayList,本篇的源码分析基于JDK8,如果有不一致的地方,可先切换到JDK8后再进行操作. 本篇的内容主要包括这几块: 1.源码结构介绍 2.源 ...

  7. 【Java入门提高篇】Day5 Java中的回调(二)

    Java中有很多个Timer,常用的有两个Timer类,一个java.util包下的Timer,一个是javax.swing包下的Timer,两个Timer类都有用到回调机制.可以使用它在到达指定时间 ...

  8. 【Java入门提高篇】Day10 Java代理——静态代理

    今天要介绍的是一个Java中一个很重要的概念--代理. 什么是代理?联系生活想想看,代理似乎并不陌生,最形象的代表便是经纪人,明星一般都有经纪人,经纪人作为中间人,负责代理明星的相关事宜,比如说,有人 ...

  9. 【Java入门提高篇】Day7 Java内部类——局部内部类

    今天介绍第二种内部类--局部内部类. 局部内部类是什么?顾名思义,那就是定义在局部内部的类(逃).开玩笑的,局部内部类就是定义在代码块.方法体内.作用域(使用花括号"{}"括起来的 ...

随机推荐

  1. ItemsPanelTemplate的用法

    项目里想用Silverlight制作工具栏,之前用的是Image和TextBlock完成的,但是代码混乱,在后来版本中突然想到ListBox可以实现这样的效果.使用后效果确实不错.下面是我的笔记 &l ...

  2. 学习总结---BGP协议

    一.可以在自治域内使用BGP作为域内协议吗? 为什么?它和OSPF的关键差异是什么? 1.BGP的全称是边界网关协议,用于自治域间的路由传递,它不像OSPF协议,其重点不在于路由的计算,而在于路由的控 ...

  3. python pip安装方法

    1.python安装,最好是按照32位的版本,64位版本有的时候出现奇怪问题. 2.python安装完成后,需要在系统的环境变量"path"中增加路径设置. 3.一般情况下,使用p ...

  4. Android基础知识04—Activity活动之间传递数据

    ------活动之间传递数据------ 向下一个活动传递数据: Intent中提供了一系列的putExtra()方法,可以把数据暂存到Intent中,启动另一个活动的时候就可以取出来. 代码: (存 ...

  5. samba服务:为在windows下操作linux的文件而生

    vi/vim编辑器好玩吗?虽有着层出不穷的语法糖但又如何与传统的sublime相媲美? 那么,来吧~ 动手跟我一起做个samba服务吧~   安装   yum -y install samba  配置 ...

  6. 表达式求值--Java实现

    /*将中缀表达式--转化为后缀表达式--属于栈的一种应用 *具体思路: *1.扫描字符串,遇到操作数字符直接不管,存到一个字符串里边 *2.操作符优先级比较--定义了方法 * 栈中优先级高:出栈存进字 ...

  7. Java基础总结--流程控制

    Java流程控制* 顺序结构--最常见的执行情况,语句按照出现的先后次序依次执行.* 判断结构--对条件进行判断,执行相应的语句.有三种常见的形式< if(判断条件){语句;}--为真执行语句, ...

  8. Golang访问Redis初体验

    go语言的client在redis官网上有很多l客户端,个人感觉redigo使用起来更人性化,重要的是源代码结构很清晰,重要的是支持管道.发布和订阅.连接池等等,所以我选择redigo作为尝试. 1. ...

  9. Linux学习(十四)磁盘格式化、磁盘挂载、手动增加swap空间

    一.磁盘格式化 分好去的磁盘需要格式化之后才可以使用.磁盘分区一般用mke2fs命令或者mkfs.filesystemtype.这个filesystemtype分为ext4,ext3,xfs等等.xf ...

  10. Ellipse

    Description There is an beautiful ellipse whose curve equation is: b > 0)" src="http:// ...