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

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

  先来看个栗子:

/**
* @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. 一步使你的asp.net网站在手机浏览器上全屏显示

    首先要加入下面的代码: <meta name="viewport" content="width=device-width, initial-scale=1.0, ...

  2. akka源码导读

    akka的actor模型提供了强大的并发,本人就akka源码进行了详细的阅读,下面是一些体会. 1.object SystemMessageList: @tailrec private[sysmsg] ...

  3. python xml sendEmail

    使用python进行发送邮件,研究的主要是用smtplib这个包,具体代码如下,eg: #!/usr/bin/python #coding=utf-8 import smtplib from emai ...

  4. 为UWP应用开启回环访问权限

    最近在项目中遇到UWP调用WCF的需求,考虑到UWP不能寄宿WCF服务(如果能,或者有类似技术,请告知),于是写了一个WPF程序寄宿WCF服务,然后再用UWP调用服务. 写的时候并没有碰到什么问题,直 ...

  5. WordPress 4.8 安装配置教程 (基于 centos 7.3, php 7.0, mysql 5.7.19, nginx 1.12.1)

    最近想要整个 blog,记录自己工作.学习中的点滴.Wordpress 自然是首选,因为内容才是关键,所以也就不怕别人说太 low.网上大部份都是讲 wordpress 配合 apache 的安装教程 ...

  6. LeetCode 111. Minimum Depth of Binary Tree (二叉树最小的深度)

    Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...

  7. 04-从零玩转JavaWeb-JVM内存详情分析

    JVM内存划分栈与栈帧 JVM将内存主要划分为: 方法区 虚拟机栈 本地方法栈 堆 程序计数器 一.方法区:存放字节码,常量 ,静态变量,是一个共享的区域 二.虚拟机栈:执行方法其实就是栈帧入栈,出栈 ...

  8. PCL 1.60 +windows+vs2010 安装与配置

    PCL简介 PCL(Point Cloud Library)是在吸收了前人点云相关研究基础上建立起来的大型跨平台开源C++编程库,它实现了大量点云相关的通用算法和高效数据结构,涉及到点云获取.滤波.分 ...

  9. 用python爬取微博数据并生成词云

    很早之前写过一篇怎么利用微博数据制作词云图片出来,之前的写得不完整,而且只能使用自己的数据,现在重新整理了一下,任何的微博数据都可以制作出来,放在今天应该比较应景. 一年一度的虐汪节,是继续蹲在角落默 ...

  10. Golang源码探索(一) 编译和调试源码

    GO可以说是近几年最热门的新型语言之一了, 一般人看到分布式和大数据就会想到GO, 这个系列的文章会通过研究golang的源代码来分析内部的实现原理, 和CoreCLR不同的是, golang的源代码 ...