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

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

  先来看个栗子:

/**
* @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. TreeViewItem实现整行选中 (两种用法)

    用法一 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quo ...

  2. CSS之 absoulte 属性

    特性: absoulte 与 float 具有相同的特性:包裹性,与破坏性  absoulte 与 float 可以交替使用  不受 relative 限制的 absoulte 定位,行为表现上可以不 ...

  3. win10 uwp 自定义控件初始化

    我遇到一个问题,我在 xaml 用了我的自定义控件,但是我给他设置了一个值,但是什么时候我才可以获得这个值? 本文告诉大家,从构造函数.loaded.Initialized 的调用过程. 用最简单的方 ...

  4. Django(一)

    Django 一.什么是web框架 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演 ...

  5. jzoj 5230 队伍统计(状压DP)

    Description 现在有n个人要排成一列,编号为1->n .但由于一些不明原因的关系,人与人之间可能存在一些矛盾关系,具体有m条矛盾关系(u,v),表示编号为u的人想要排在编号为v的人前面 ...

  6. LINUX 笔记-vmstat命令

    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff ...

  7. JAVA基础知识总结:十

    一.抽象类 1.定义 当多个类中出现相同功能,但是功能主体是不同的,这是可以进行向上抽取的,只抽取功能的定义部分,使用抽象类实现 抽象类的存在就是为了被继承 2.使用 abstract 3.抽象类的特 ...

  8. LeetCode 191. Number of 1 bits (位1的数量)

    Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also know ...

  9. Fastify 系列教程四 (求对象、响应对象和插件)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...

  10. 用css属性画出一棵圣诞树

    对于学习前端的童鞋,css的掌握是必须的.今天就来实现用css画出一棵圣诞树. 主要练习的是css里面border的练习与掌握程度. 在body创建一个主区域<div></div&g ...