##################################################

目录

接口基础知识

什么是接口

如何定义和实现接口

接口表示一种能力

为什么需要接口

使用接口实现防盗门功能

扩展接口的能力

使用接口的好处

接口表示一种约定

使用接口实现打印机功能

面向接口编程

何谓面向接口

面向接口编程的好处


##################################################

接口基础知识

——————————

什么是接口

接口也是 Java 中非常重要的内容

接口和多态及抽象类有非常密切的关系

在生活中 接口是一套规范

满足这个规范的设备就可以将她们组装到一起从而实现该设备的功能

以 USB 为例子

USB 接口实际上是某些企业和组织等制定的一种约定或标准

规定了接口的大小、形状、各引脚信号的范围和含义、通信速度、通信流程等

并按照该约定或标准来设计各种设备 例如

U 盘

USB 风扇

USB 键盘

都可以插到 USB 口上正常工作

而在软件中 接口同样是一种规范和标准

她们可以约束类的行为 是一些方法特征的集合 但是没有方法的实现

从这个角度来看 接口可以看作是一种特殊的 抽象类

但是采用与抽象类完全不同的语法来表示 两者的设计理念也是完全不同的

抽象类利于代码复用 接口利于代码的扩展和维护

Java 中接口的定义语法和类实现接口的语法如下:

[修饰符] interface 接口名 extends 父接口_1, 父接口_N {/* 常量定义 *//* 方法定义 */
}
class 类名 extends 父类名 implements 接口_1, 接口_N {/* 类成员 */
}

接口的命名规则与类相同

如果修饰符是 public 则该接口在整个项目中可见

如果省略修饰符 则该接口只能在当前包可见

接口中可以定义常量 不能定义变量

接口中的属性都会自动用 public static final 修饰

即接口中的属性都是全局静态常量

接口中的常量必须在定义时指定初始值:

public static final int PO = 3.14;
int PI = 3.14;    // 在接口中这两个定义语句效果完全相同
int PI;    // 错误! 在接口中必须指定初始值 在类中会有默认值

接口中所有方法都是抽象方法

接口中方法都会自动用 public abstract 修饰

即接口中只有全局抽象方法

和抽象类一样 接口也不能实例化

接口中也不能有构造方法

接口之间可以通过 extends 实现继承关系

一个接口可以继承多个接口 但是接口不能继承类!

接口的实现类必须实现接口的全部方法

否则必须定义为抽象类!

——————————

如何定义和实现接口

一个类只能有一个直接父类 但可以通过 implements 实现多个接口

当类在继承父类的同时又实现了多个接口时 extends 关键字必须位于 implements 关键字之间

下面就使用 Java 接口来模拟生活中的  USB 接口

在现实生活中 USB 接口相关工作都是按照如下步骤进行:

约定 USB 接口标准

制作符合 USB 接口约定的各种具体设备

将 USB 设备插到 USB 接口上进行工作

我们可以先定义 USB 接口 通过 service 方法提供服务:

interface UsbInterface {
/* USB 接口 */void service ();    // USb 接口提供的服务方法
}

然后定义 U 盘类 实现 USB 接口中的 services 方法进行数据传输

class UDisk implements UsbInterface {
/* U 盘类 */public void service () {/* 实现 USB 接口的服务方法 */System.out.println ( "连接 USB 接口开始传输数据.." );}
}

定义 USB 风扇类 实现 USB 接口中的 services 方法获得电流使风扇转动:

class UFan implements UsbInterface {
/* USB 风扇类 */public void service () {/* 实现 USB 接口中的 service 方法 */System.out.println ( "连接 USB 口, 获得电流, 风扇开始转动!呼呼呼" );}
}

测试类 使用 U 盘传输数据使用 USB 风扇吹风:

public class Test {
/* 测试类 */public static void main (String [] args) {// USB 盘UsbInterface uDisk = new UDisk();   // USB 盘向上转换为 USB 接口类型uDisk.service (); // 调用传输数据服务// USB 风扇UsbInterface uFan = new UFan();uFan.service();}
}

我们声明了接口 UsbInterface

实例化接口的实现类 uDisk 和 Ufan 类型对象

遵循了向上转型的规则

运行结果如下:

C:\Users\byme\javaTest>javac Test.javaC:\Users\byme\javaTest>java Test
连接 USB 接口开始传输数据..
连接 USB 口, 获得电流, 风扇开始转动!呼呼呼C:\Users\byme\javaTest>

##################################################

接口表示一种能力

——————————

为什么需要接口

现在假如有一个需求 要求实现防盗门的功能:

门有 开/关 两个功能

锁有 上锁/开锁 两个功能

首先防盗门是一个门 她有一把锁

按照面向对象的思想 可以将门和锁分别定义为抽象类

但是不能让防盗门在继承门的同时又继承锁:

第一 防盗门不是锁 不符合继承中 is a 的关系

第二 Java 仅仅支持单继承

如何解决这个问题呢?现在就需要用到接口了!

可以将锁定义为接口 让防盗门继承门 实现锁的接口

——————————

使用接口实现防盗门功能

前面经过模拟 USB 接口 我们已经了解到 Java 接口的语法和规则

现在就使用接口来实现防盗门功能

防盗门是一个门 符合 is a 的关系 可以抽象出一个门类

防盗门有一把锁 代表她有 上锁/开锁 的能力 表达的是 has a 的关系

这里可以将锁定义成接口 让防盗门继承门类实现锁接口

步骤如下:

定义抽象类 Door 具备开关锁功能

定义 Lock 接口具备上锁开锁的能力

定义 TheftproofDoor 类继承 Door 类的同时实现 Lock 接口

编写测试类 实现防盗门的开关和上锁开锁的功能

定义抽象类 Door 具备开关锁功能:

abstract class Door {
/* 门类 */public abstract void open();    // 抽象开锁方法public abstract void close();  // 抽象关锁方法
}

定义 Lock 接口 具备上锁开锁的能力:

interface Lock {
/* 锁接口 */void lockUp(); // 上锁服务void openLock(); // 开锁服务
}

定义 TheftproofDoor 类继承 Door 类的同时实现 Lock 接口:

class TheftproofDoor extends Door implements Lock {
/* 继承门类 实现接口的方法 */public void open() {/* 实现开门方法 */System.out.println ( "用力推,门开了……" );}public void close() {/* 实现关门方法 */System.out.println ( "轻轻拉,门关上了……" );}public void lockUp() {/* 实现上锁服务 */System.out.println ( "插进钥匙,向左旋转钥匙三圈,锁上了,拔出钥匙!" );}public void openLock () {/* 实现开锁服务 */System.out.println ( "插进钥匙,向右旋转钥匙三圈,锁打开了,拔出钥匙.." );}
}

编写测试类 实现防盗门的开关和上锁开锁的功能:

public class Test {
/* 测试类 */public static void main (String[] args) {TheftproofDoor tfd = new TheftproofDoor();tfd.close ();  // 关门tfd.lockUp (); // 上锁tfd.openLock ();   // 开锁tfd.open ();   // 开门}
}

运行测试:

C:\Users\byme\javaTest>javac Test.javaC:\Users\byme\javaTest>java Test
轻轻拉,门关上了……
插进钥匙,向左旋转钥匙三圈,锁上了,拔出钥匙!
插进钥匙,向右旋转钥匙三圈,锁打开了,拔出钥匙..
用力推,门开了……C:\Users\byme\javaTest>

%%%%%

扩展接口的能力

现在我们应该可以理解接口表示一种能力

一个类实现了某个接口 就表示这个类具备了某种能力

其实生活中这样的例子还有很多 抽象来说:

如木匠、铁匠并不是某个接口而代表一种能力

招聘木匠、铁匠就是招聘具备该能力的人

所以生活中一个人可以具有多项能力

程序中一个类可以实现多个接口

既然接口代表一种能力 那么我们现在就在打开、关闭防盗门的基础上扩展防盗门的功能

例如 防盗门要增加一个门铃 主要功能是拍照存档

主人不在家 当有客人来访问时 只要来人轻按门铃便自动拍照存储

现在为防盗门增加一种拍照能力:

interface DoorBell {
/* 门铃接口 */void takePictures (); // 拍照存档服务
}

然后在 TheftproofDoor 类中实现该接口能力 在测试类中测试功能:

abstract class Door {public abstract void open();public abstract void close();
}interface Lock {void lockUp();void openLock();
}class TheftproofDoor extends Door implements Lock, DoorBell {
/* 关联了两个接口 锁和门铃 */public void open() {System.out.println ( "用力推,门开了……" );}public void close() {System.out.println ( "轻轻拉,门关上了……" );}public void lockUp() {System.out.println ( "插进钥匙,向左旋转钥匙三圈,锁上了,拔出钥匙!" );}public void openLock () {System.out.println ( "插进钥匙,向右旋转钥匙三圈,锁打开了,拔出钥匙.." );}public void takePictures () {/* 实现拍照能力 */System.out.println ( "铃... 咔嚓... 照片已存储!" );}
}public class Test {public static void main (String[] args) {TheftproofDoor tfd = new TheftproofDoor();tfd.close ();tfd.lockUp ();tfd.takePictures (); // 有客人来按铃 自动拍照tfd.openLock ();tfd.open ();}
}interface DoorBell {
/* 门铃接口 */void takePictures (); // 拍照存档服务
}

运行结果如下:

C:\Users\byme\javaTest>javac Test.javaC:\Users\byme\javaTest>java Test
轻轻拉,门关上了……
插进钥匙,向左旋转钥匙三圈,锁上了,拔出钥匙!
铃... 咔嚓... 照片已存储!
插进钥匙,向右旋转钥匙三圈,锁打开了,拔出钥匙..
用力推,门开了……C:\Users\byme\javaTest>

%%%%%

使用接口的好处

接口不仅弥补了 Java 只能单继承的缺点 还利于代码的扩展和维护

接口类似于一个组件 需要时可以自由组装

从使用角度来讲 接口和抽象类的区别在于

抽象类利于代码复用

接口利于代码维护

    在 Java API 中 可以发现很多接口名都是以
able为后缀的就是表示
可以做某件事例如
Serializable
Comparable
Iterable等在微软公司的 .NET 中也有很多接口名以
able后缀例如
IComparable
INullable
IClonable等 也表示同样的意思

##################################################

接口表示一种约定

——————————

使用接口实现打印机功能

要求实现打印机打印功能

打印机的墨盒可能是彩色的 也可能是黑白的

所用的纸张可以有多种类型 例如 A4、B5 等

并且墨盒和纸张都不是打印机厂商提供的

打印机厂商如何避免自己的打印机与市场上的墨盒、纸张不符呢?

有效解决该问题的途径是制定墨盒、纸张的约定或者标准然后打印机厂商按照约定对墨盒、纸张提供支持

无论最后使用的是哪个厂商提供的墨盒或纸张 只要符合统一的约定打印机都可以打印

Java 中的接口表示这样一种约定

通过 Java 实现打印机的具体步骤如下:

定义墨盒接口 InkBox 约定墨盒的标准

定义纸张接口 Paper 约定纸张的标准

定义打印机类、引用墨盒接口、纸张接口实现打印功能

墨盒厂商按照 InkBox 接口实现 ColorInkBox类和 GrayInkBox 类

纸张厂商按照 Paper 接口实现 A4Paper 类和 B5Paper 类

组装打印机 让打印机通过不同墨盒和纸张实现打印功能

InkBox.java code:

public interface InkBox {
/* 墨盒接口 */public String getColor ();    // 约定墨盒有颜色
}

Paper.java code:

public interface Paper {
/* 纸张接口 */public String getSize (); // 约定墨盒的大小
}

Printer.java code:

public class Printer {
/* 打印机类 */InkBox inkBox;    // 引用墨盒接口Paper paper;   // 引用纸张接口public void setInkBox (InkBox inkBox) {/* 设置墨盒 */this.inkBox = inkBox;    // 获取墨盒颜色}public void setPaper (Paper paper) {/* 设置纸张 */this.paper = paper;    // 获取纸张大小}public void print () {/* 使用墨盒在纸张上打印 */System.out.printf ( "使用%s墨盒在%s纸张上开始打印..\n", inkBox.getColor (), paper.getSize () );}
}

ColorInkBox.java code:

public class ColorInkBox implements InkBox {
/* 彩色墨盒类 实现墨盒接口 */public String getColor () {/* 实现获取墨盒颜色服务 */return "彩色";}
}

GrayInkBox.java code:

public class GrayInkBox implements InkBox {
/* 黑白墨盒类 实现墨盒接口 */public String getColor () {/* 实现获取墨盒颜色能力 */return "黑白";}
}

A4_Paper.java code:

public class A4_Paper implements Paper {
/* A4 纸类 实现墨盒纸张接口 */public String getSize() {/* 实现获取纸张大小服务 */return "A4";}
}

B5_Paper.java code:

public class B5_Paper implements Paper {
/* B5 纸类 实现墨盒纸张接口 */public String getSize() {/* 实现获取纸张大小能力 */return "B5";}
}

Test.java code:

public class Test {
/* 测试类 */public static void main ( String [] args ) {/* main 方法中组装打印机并通过不同墨盒纸张实现打印 */// 定义打印机InkBox inkBox = null; // 引用 InkBox 墨盒接口对象 inkBox 对象值为空墨盒Paper paper = null;  // 引用 Paper 纸张接口对象 paper 对象值为空纸张Printer printer = new Printer();   // 实例化一个打印机类的 printer 打印机对象// 使用黑白墨盒在 A4 纸张上打印inkBox = new GrayInkBox();   // inkBox 墨盒接口对象的值为黑白墨盒类paper = new A4_Paper ();   // 纸张接口对象向上转换为 A4 纸张类型printer.setInkBox ( inkBox ); // 设置黑白墨盒printer.setPaper ( paper );    // 设置 A4 纸printer.print (); // 开始打印// 使用彩色墨盒在 A4 纸张上打印inkBox = new ColorInkBox();  // 更改墨盒为彩色墨盒/* 纸张不变 */printer.setInkBox ( inkBox ); // 设置黑白墨盒printer.print ();  // 开始打印// 使用黑白墨盒在 B5 纸张上打印inkBox = new GrayInkBox();   // 更改墨盒为黑白墨盒paper = new B5_Paper ();   // 更改纸张为 B5 纸printer.setInkBox ( inkBox );  // 设置黑白墨盒printer.setPaper ( paper );    // 设置 B5 纸printer.print (); // 开始打印// 使用彩色墨盒在 B5 纸张上打印inkBox = new ColorInkBox();  // 更改墨盒为彩色墨盒/* 纸张不变 */printer.setInkBox ( inkBox ); // 设置彩色墨盒printer.print ();  // 开始打印}
}

cmd demo:

C:\Users\byme\javaTest>dir *.java驱动器 C 中的卷是 System_8.1卷的序列号是 B6F6-A064C:\Users\byme\javaTest 的目录2022/06/22  10:33               179 A4_Paper.java
2022/06/22  10:33               179 B5_Paper.java
2022/06/22  10:28               152 ColorInkBox.java
2022/06/22  10:29               151 GrayInkBox.java
2022/06/22  10:16                94 InkBox.java
2022/06/22  10:18                92 Paper.java
2022/06/22  10:53               488 Printer.java
2022/06/22  10:55             1,342 Test.java8 个文件          2,677 字节0 个目录  6,756,528,128 可用字节C:\Users\byme\javaTest>javac Test.javaC:\Users\byme\javaTest>dir *.class驱动器 C 中的卷是 System_8.1卷的序列号是 B6F6-A064C:\Users\byme\javaTest 的目录2022/06/22  10:52               285 A4_Paper.class
2022/06/22  10:52               285 B5_Paper.class
2022/06/22  10:52               297 ColorInkBox.class
2022/06/22  10:52               295 GrayInkBox.class
2022/06/22  10:52               135 InkBox.class
2022/06/22  10:52               132 Paper.class
2022/06/22  10:53               801 Printer.class
2022/06/22  10:55               622 Test.class8 个文件          2,852 字节0 个目录  6,756,528,128 可用字节C:\Users\byme\javaTest>java Test
使用黑白墨盒在A4纸张上开始打印..
使用彩色墨盒在A4纸张上开始打印..
使用黑白墨盒在B5纸张上开始打印..
使用彩色墨盒在B5纸张上开始打印..C:\Users\byme\javaTest>

此时我们理解了接口表示一种约定

其实生活中这样的例子还有很多

例如两相电源插座中接头的形状、两个接头间的距离和两盒接头的电压都遵循统一的约定

在变量对象编程中提倡面向接口编程而不是面向实现编程

##################################################

面向接口编程

——————————

何谓面向接口

什么是面向接口编程呢?

    简单来说
如果打印机厂商只面向一家或几家厂商的墨盒产品规格生产打印机而没有一个统一的约定
就无法使用更多厂商的墨盒如果这家墨盒厂商倒闭了
那么打印机就无用武之地了这是因为她们彼此之间依赖性太强了
或者说耦合性太强了而如果按照统一的约定生产打印机和墨盒就不会存在这个问题了打印机类实现了面向接口编程的思想Printer/打印机 类的两个属性使用了 InkBox/墨盒 与 Paper/纸张 两个接口就可以接收实现了这两个接口的所有类的对象!即使是新推出的墨盒类型 只要遵守该接口的约定 就能够被接收!
而如果使用面向实现编程
则两个属性类型使用 GrayInkBox/黑白墨盒 和 B5_Paper/B5 纸 大大限制了打印机的使用范围……
无法对新推出的 ColorInkBox/彩色墨盒 提供支持
这也体现了多态的可扩展课维护的特性

——————————

面向接口编程的好处

接口体现了约定和实现相分离的原则

通过面向接口编程可以降低代码间的耦合性 提高代码的可扩展性和可维护性

面向接口编程就意味着:

开发系统时

主体构架使用接口

接口构成系统的骨架

这样就可以通过更换接口的类来实现更换系统!

    面向接口编程可以实现接口和实现的分离这样做最大的好处就是能够在客户端未知的情况下修改实现代码那么怎样抽象出接口呢?
一种是用在层和层之间的调用层层之间最忌讳耦合度过高或修改过于频繁!设计优秀的接口能够解决这个问题
另一种是使用在那些不稳定的部分上如果某些需求的变化性很大那么定义接口也是一种解决办法!设计良好的接口就像日常使用的万用插座不论插头如何变化都可以使用!最后强调一点:
良好的接口定义一定是来自于需求的绝对不是程序员绞尽脑汁想出来的

13.0_[Java 面向接口]-类和接口相关推荐

  1. 几个重要的java数据库访问类和接口

    编写访问数据库的Java程序还需要几个重要的类和接口. DriverManager类 DriverManager类处理驱动程序的加载和建立新数据库连接.DriverManager是java.sql包中 ...

  2. java接口版本控制_为什么要在Java中控制类和接口的可见性

    java接口版本控制 维护是软件开发的重要方面之一,并且经验证明,保持较低组件可视性的软件比暴露更多组件的软件更易于维护. 您不会在一开始就意识到它,但是在重新设计应用程序时会严重错过它. 由于保持向 ...

  3. JAVA笔记:shape类(接口,继承,lambda表达式...)

    目录 写一段程序,实现shape面积,并可以对面积大小排序 定义父类shape类,并定义方法Area() 定义第一个子类Circle类 定义第二个子类Rect类 定义接口Comparator,并写入c ...

  4. effective java 读书笔记——类和接口

    上周因为准备考试等一堆原因,没空看书,今天补上一点. 类和接口是java程序设计语言的核心,它们也是java语言的基本抽象单元,java语言提供了很多强大的基本元素,供程序员设计类和接口,这一章讲的是 ...

  5. java interfave_高级类特性----接口(intertface)

    接 口 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法.但是,Java不支持多重继承.有了接口,就可以得到多重继承的效果. 接口(interface)是抽象方法和常量值的定义的集合. 从本 ...

  6. Java泛型(类、接口、方法)及通配符

    什么是泛型? 泛型,即"参数化类型".例如:定义方法时有形参,然后调用此方法时传递实参.参数化类型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形 ...

  7. 用户类java,通过Java中的类和接口实现不同的用户类型

    问题 我对设计模式相当陌生,并且一直在研究这本书,Head First Design Patterns.我需要实现一个有3种用户的系统:会员,主持人,管理员.主持人可以执行会员可以执行的所有操作,还可 ...

  8. 探讨Java I/O类和接口

    (输出)Output:程序---->数据源(如某个文件) (输入)Input:数据源---->程序 Java.io定义的I/O类如下表所示: BufferedInputStream Buf ...

  9. java提交姓名接口,【填空题】Java 程序的 类或接口的名字必须和所在Java源文件名相同。...

    税收实体法指拥有税收立法权的立法主体为了保证税收实体法所规定的权利与义务关系的实现而制 原产于我国参加的含有关税优惠条款的区域性贸易协定有关缔约方的进口货物适用().A.协定税率B. 干燥的沥青或混凝 ...

最新文章

  1. Python:线程之定位与销毁
  2. 实施文档_Word 2010文档处理案例教程
  3. python3安装pip3-python3安装pip3
  4. boost::multiprecision模块complex128相关的测试程序
  5. np.dot()函数用法(亲测矩阵算法)
  6. Innodb中MySQL如何快速删除2T的大表
  7. 数据结构 二、向量(接口与实现and可扩容向量)
  8. mysql用户可以localhost登陆_【单选题】登陆MySQL服务器,默认的用户名为 A. user B. pwd C. root D. localhost...
  9. 新一代企业级大数据应用方案
  10. Sqlist 插入、删除元素
  11. 江娱互动:游戏领域 Serverless 架构探索之路
  12. 原来互联网公司想裁员还能这样玩?
  13. 为什么ios比android流畅
  14. win11蓝牙无法使用 Windows11蓝牙无法使用的解决方法
  15. faiss 相似特征向量搜索
  16. 圆形标定板_机器视觉学习笔记(2)--如何检测圆点标定板
  17. 软件编程控制硬件的关键——寄存器
  18. 随笔:读书笔记--《CEO说像企业家一样思考》拉姆·查兰
  19. 详解【负载均衡】(负载均衡算法、一致性hash、负载均衡架构分析)
  20. Word:无法启动转换器WPFT532 WPFT632 解决方法

热门文章

  1. 如何写一篇好的技术文档
  2. Megacli常用命令汇总
  3. 预防XSS——后端HttpUtility.HtmlEncode,AntiXssEncoder.HtmlEncode方法;前端htmlencode,htmldecode,JavaScriptEncode
  4. 路由守卫(登录_vue3)
  5. 网易游戏岗位大揭秘——我在网易做测试开发(QA)
  6. The 2021 ICPC Asia Shanghai Regional Programming Contest 2021ICPC上海站VP
  7. IntelliJ:idea取消启动时的默认工作空间,打开欢迎页面
  8. 如何入门“动物杂交:新视野”
  9. Android Qcom USB Driver学习(四)
  10. 【内附独家PPT】CynosDB for MySQL 计算存储分离架构的实现和优化