文/沉默王二

曹操在《短歌行》中为杜康酒打过一个价值一亿个亿的广告——“何以解忧,唯有杜康”,我替曹操感到惋惜的是他本人并不会收到这笔不菲的代言费。想一想,要是三国时期的明星人物们有这个代言意识的话,保证各家的军费收入会多出来一个重量级的来源。

不过,酒真的能解忧吗?我不大敢相信。李白就曾质疑过:“举杯消愁愁更愁,抽刀断水水更流。”我和李白持相同的观点,酒啊,真的不容易解忧,但绝对可以增加作者莫名的写作冲动。

我在写本文之前就小酌了一杯,一不小心激发了我强烈的创作欲望。不过我要奉劝各位,寒冬之际,如果遇到烦心事,千万别肆意地追求一醉方休,万事要懂得适可而止

01 抽象类

一种比较苍白的说法是:在Java中,通过关键字abstract定义的类叫做抽象类。Java是一门面向对象的语言,因此所有的对象都是通过类来描述的;但反过来,并不是所有的类都是用来描述对象的,抽象类就是其中的一种。

以下示例展示了一个简单的抽象类:

// 个人认为,一名教练必须攻守兼备
abstract class Coach {
    public abstract void defend();     public abstract void attack();
}

在一个抽象类中,至少有一个抽象方法(通过关键字abstract定义的方法,并且没有方法体,如上例中的defend()方法和attack()方法),否则就没有必要称之为抽象类。需要注意的是,抽象类是不能实例化的! 它需要被一个子类继承,就像以下示例那样。

abstract class Coach {
    public abstract void defend();     public abstract void attack();
} class Hesai extends Coach {     @Override
    public void defend() {
        System.out.println("防守赢得冠军");
    }     @Override
    public void attack() {
        System.out.println("控球是把双刃剑");
    }
} public class Demo {
    public static void main(String[] args) {
        Coach moliniao = new Hesai();
        moliniao.defend();
        moliniao.attack();
    }
}

我们都知道,一个好的教练,必须攻守兼备,但每个教练的进攻理念和防守理念不尽相同。因此,我在教练这个抽象类(Coach)中定义两个抽象方法,一个进攻(attack)一个防守(defend),这两个方法的具体实现都要由抽象类的子类确定,抽象类本身并不负责。

我们也都知道,何塞·穆里尼奥是足球界的顶级教练。他是我最爱的足球教练,没有之一。尽管他在曼联的失败有他自身的原因,但我依然崇拜他,因为:“请不要说我傲慢,因为我只是实话实说,我是欧洲冠军,因此我并非籍籍无名,而是特殊的一个!”他是固执的反控球主义者,坚信控球是把双刃剑,防守赢得冠军。

好了,对于抽象类我们简单总结一下:

1、抽象类不能被实例化。
2、抽象类应该至少有一个抽象方法,否则它没有任何意义。
3、抽象类中的抽象方法没有方法体。
4、抽象类的子类必须给出父类中的抽象方法的具体实现,除非该子类也是抽象类。

02 接口

我们知道,有抽象方法的类被称为抽象类,也就意味着抽象类中还能有不是抽象方法的方法。这样的类就不能算作纯粹的接口,尽管它也可以提供接口的功能——只能说抽象类是普通类与接口之间的一种中庸之道。

接口(英文:Interface),在Java中是一个抽象类型,是抽象方法的集合;接口通过关键字interface来定义。接口与抽象类的不同之处在于:

1、抽象类可以有方法体的方法,但接口没有。
2、接口中的成员变量隐式为static final,但抽象类不是的。
3、一个类可以实现多个接口,但只能继承一个抽象类。

以下示例展示了一个简单的接口:

// 隐式的abstract
interface Coach {
    // 隐式的public
    void defend();
    void attack();
}

接口是隐式抽象的,所以声明时没有必要使用abstract关键字;接口的每个方法都是隐式抽象的,所以同样不需要使用abstract关键字;接口中的方法都是隐式public的。

和抽象类一样,接口也不能直接被实例化,它需要一个类来实现它,就像以下示例展示那样。

class Hesai implements Coach {

    @Override
    public void defend() {
        System.out.println("防守赢得冠军");
    }     @Override
    public void attack() {
        System.out.println("控球是把双刃剑");
    }
} public class Demo2 {
    public static void main(String[] args) {
        Coach moliniao = new Hesai();
        moliniao.defend();
        moliniao.attack();
    }
}

实现一个接口需要用到关键字implements,它表示:“我这个类遵从了接口的协议,如果你想使用我,看接口就行了,具体实现不用关心。”

03 多重实现

在现实生活中,何塞·穆里尼奥不止是一名足球教练,他还是一个值得被尊重的英雄——凭借自身的努力,他从一名籍籍无名的跟班翻译,逐渐蜕变为一名家喻户晓的顶级教练。

如果要在程序的世界里体现何塞·穆里尼奥的多重角色,就可以使用接口,就像以下示例展示那样。

package com.cmower.java_demo.nine.inf;

interface Coach {
    // 隐式的public
    void defend();
    void attack();
} interface Hero {
    void fight();
} class Hesai implements Coach, Hero {     @Override
    public void defend() {
        System.out.println("防守赢得冠军");
    }     @Override
    public void attack() {
        System.out.println("控球是把双刃剑");
    }     @Override
    public void fight() {
        System.out.println("只要一息尚存,就应该战斗到最后");
    }
} public class Demo2 {
    public static void defend(Coach coach) {
        coach.defend();
    }     public static void fight(Hero hero) {
        hero.fight();
    }     public static void main(String[] args) {
        Hesai moliniao = new Hesai();
        defend(moliniao);
        fight(moliniao);
    }
}

可以看到,创建的Hesai对象可以向上转型为Coach和Hero,然后调用各自接口中实现的具体方法,因为Hesai这个类同时实现了两个接口,分别是Coach和Hero(class Hesai implements Coach, Hero,接口之间通过英文逗号隔开)。

04 接口在应用中常见的三种模式

在编程领域,好的设计模式能够让我们的代码事半功倍。在使用接口的时候,经常会用到三种模式,分别是策略模式、适配器模式和工厂模式。

1)策略模式

策略模式的思想是,针对一组算法,将每一种算法封装到具有共同接口的实现类中,接口的设计者可以在不影响调用者的情况下对算法做出改变。示例如下:

// 接口:教练
interface Coach {
    // 方法:防守
    void defend();
} // 何塞·穆里尼奥
class Hesai implements Coach {     @Override
    public void defend() {
        System.out.println("防守赢得冠军");
    }
} // 德普·瓜迪奥拉
class Guatu implements Coach {     @Override
    public void defend() {
        System.out.println("进攻就是最好的防守");
    }
} public class Demo {
    // 参数为接口
    public static void defend(Coach coach) {
        coach.defend();
    }     public static void main(String[] args) {
        // 为同一个方法传递不同的对象
        defend(new Hesai());
        defend(new Guatu());
    }
}

Demo.defend()方法可以接受不同风格的Coach,并根据所传递的参数对象的不同而产生不同的行为,这被称为“策略模式”。

2)适配器模式

适配器模式的思想是,针对调用者的需求对原有的接口进行转接。生活当中最常见的适配器就是HDMI(英语:High Definition Multimedia Interface,中文:高清多媒体接口)线,可以同时发送音频和视频信号。适配器模式的示例如下:

interface Coach {
    void defend();
    void attack();
} // 抽象类实现接口,并置空方法
abstract class AdapterCoach implements Coach {
    public void defend() {};
    public void attack() {};
} // 新类继承适配器
class Hesai extends AdapterCoach {
    public void defend() {
        System.out.println("防守赢得冠军");
    }
} public class Demo {
    public static void main(String[] args) {
        Coach coach = new Hesai();
        coach.defend();
    }
}

Coach接口中定义了两个方法(defend()和attack()),如果类直接实现该接口的话,就需要对两个方法进行实现。

如果我们只需要对其中一个方法进行实现的话,就可以使用一个抽象类作为中间件,即适配器(AdapterCoach),用这个抽象类实现接口,并对抽象类中的方法置空(方法体只有一对花括号),这时候,新类就可以绕过接口,继承抽象类,我们就可以只对需要的方法进行覆盖,而不是接口中的所有方法。

3)工厂模式

所谓的工厂模式理解起来也不难,就是什么工厂生产什么,比如说宝马工厂生产宝马,奔驰工厂生产奔驰,A级学院毕业A级教练,C级学院毕业C级教练。示例如下:

// 教练
interface Coach {
    void command();
} // 教练学院
interface CoachFactory {
    Coach createCoach();
} // A级教练
class ACoach implements Coach {     @Override
    public void command() {
        System.out.println("我是A级证书教练");
    } } // A级教练学院
class ACoachFactory implements CoachFactory {     @Override
    public Coach createCoach() {
        return new ACoach();
    } } // C级教练
class CCoach implements Coach {     @Override
    public void command() {
        System.out.println("我是C级证书教练");
    } } // C级教练学院
class CCoachFactory implements CoachFactory {     @Override
    public Coach createCoach() {
        return new CCoach();
    } } public class Demo {
    public static void create(CoachFactory factory) {
        factory.createCoach().command();
    }     public static void main(String[] args) {
        // 对于一支球队来说,需要什么样的教练就去找什么样的学院
        // 学院会介绍球队对应水平的教练。
        create(new ACoachFactory());
        create(new CCoachFactory());
    }
}

有两个接口,一个是Coach(教练),可以command()(指挥球队);另外一个是CoachFactory(教练学院),能createCoach()(教出一名优秀的教练)。然后ACoach类实现Coach接口,ACoachFactory类实现CoachFactory接口;CCoach类实现Coach接口,CCoachFactory类实现CoachFactory接口。当需要A级教练时,就去找A级教练学院;当需要C级教练时,就去找C级教练学院。

依次类推,我们还可以用BCoach类实现Coach接口,BCoachFactory类实现CoachFactory接口,从而不断地丰富教练的梯队。

05 总结

尽管接口使得抽象更进一步,但任何抽象性都应该根据真正的需求而产生,因此恰当的原则是优先选择类而不是接口,只有在真正需要接口的时候再重构代码。

Java接口的实例应用:致敬我的偶像——何塞·穆里尼奥的更多相关文章

  1. Java 接口基础详解

    目录 Java接口示例 实现一个接口 接口实例 实现多个接口 方法签名重叠 接口变量 接口方法 接口默认方法 接口与继承 继承与默认方法 接口与多态性 在Java中,接口是一个抽象类型,有点类似于类, ...

  2. 转载:Java的接口及实例

    转自:http://blog.csdn.net/liujun13579/article/details/7736116/ 一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特 ...

  3. 转:十九、Java的接口及实例

    http://blog.csdn.net/liujun13579/article/details/7736116 一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合 ...

  4. Java的接口及实例

    一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为( ...

  5. java接口传递数据的实例

    我们要讲E类中的数据变化通知A类,这样通过接口F来实现.具体原理就是E的每次数据改变都让其通知接口:而A类继承接口,所以每次E的调用接口都会触发A类的数据更改事件的触发. 首先创建一个类E: publ ...

  6. java接口

    一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为( ...

  7. Java WebService入门实例

    Web Services是由企业发布的完成其特定商务需求的在线应用服务,其他公司或应用软件能够通过Internet来访问并使用这项在线服务. Web Service的关键技术和规则: 1.XML:描述 ...

  8. JAVA上百实例源码以及开源项目

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级.中级.高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情.执着,对IT的憧憬. ...

  9. python面向对象进阶 反射 单例模式 以及python实现类似java接口功能

    本篇将详细介绍Python 类的成员.成员修饰符.类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和特性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存 ...

随机推荐

  1. MSSql-1内部数据库版本号

    源SQL Server版本 内部数据库版本 SQL Server 2017 869 SQL Server 2016 782 SQL Server 2012 706 SQL Server 2008 R2 ...

  2. 第一章 Java概述

    1.JAVA分类 JAVA SE:基础核心(面向对象.API.JVM...) JAVA ME:(游戏.通讯开发) JAVA EE(JSP/Sevlet\EJB\服务开发.企业应用)   2.JAVA语 ...

  3. 2018-2019-3 网络对抗技术 20165235 Exp3 免杀原理与实践

    2018-2019-3 网络对抗技术 20165235 Exp3 免杀原理与实践 基础问题回答 杀软是如何检测出恶意代码的? 1.对某个文件的特征码进行分析,(特征码就是一类恶意文件中经常出现的一段代 ...

  4. DAY1 VS2017&CUDA10.01环境搭建

    Visual Studio工程配置情况: VC++目录配置: C:\ProgramData\NVIDIA Corporation\CUDA Samples\v10.\common\lib\x64 C: ...

  5. hbase_1

    常见的RDBMS:(数据库排行) ** mysql --开源[社区版] .收费[企业版] --市场占有率高.web领域被广泛使用 ** 2008年被oracle收购 ** mysql主从架构[集群的一 ...

  6. 三、OpenStack创建域,项目,用户和角色,验证,创建客户端脚本

    一.Identity服务为每个OpenStack服务提供身份验证服务. 身份验证服务使用域,项目,用户和 角色的组合. 1.创建service 项目 # openstack project creat ...

  7. Win Server 2003 10条小技巧

    微软推出Windows Server 2003已经有一段时间了,但是,由于它是一个面向企业用户的服务器操作系统,所以,没有引起更多个人用户的注意.实际上,简单地改变一下系统的设置,您也可以将Windo ...

  8. Run Keyword And Ignore Error,Run Keyword And Return Status,Run Keyword And Continue On Failure,Run Keyword And Expect Error,Wait Until Keyword Succeeds用法

    *** Test Cases ***case1 #即使错误也继续执行,也不记录失败,且可以返回执行状态和错误信息 ${Run Keyword And Ignore Error status} ${st ...

  9. 2018-4-5-MEMS

    微机电系统,研究生在学习纳米操作方面的知识的时候了解过一些,有时间的话写点东西温故知新.

  10. Spring系列__02IOC模块简介

    Spring的两大核心功能就是IOC和AOP,这篇文章主要介绍IOC. 简单来说,在面向对象思想下,A类中有一个B类的属性, 那么我们在创建A类时往往需要同时创建一个B类的对象,以便A类对其进行调用. ...