第13章-接口
概述
- 在实际的应用过程中,有一些特定的单一行为,是跨多个不同风格的系列类,如克隆、系列化、比较、迭代等
- 针对这种行为,可定义为接口,并在需要的地方实现这个接口即可让实现的类具备该行为
- Java自带类库中有大量的应用,像String类型、包装类等类型都实现了接口Serializable、Comparable
- 生活场景
- 作为一个人类的对象,具备一般从的特征和行为;但学习了Java技术后,就新多了写代码个能力(行为),这种叠加的能力,可使用接口描述
- 某些游戏中,英雄都有自己的基本皮肤、技能;但也可以在实战过程中,通过购买不同道具,叠加一些英雄本身不具备的技能,这样的技能,就可以使用接口描述
- ...
定义接口
语法规则
关键字是interface
语法规则如下:
/**
* 【接口】
*/
访问修饰符 interface 接口名称{
//【静态常量】接口不具备属性,定义属性默认会加上static final关键字
数据类型 常量名 = 常量值;
//【抽象方法】,接口中的所有方法都是抽象方法,没有实现逻辑,只有方法声明(确定方法签名)
返回值类型 方法名();
}语法解释 :
- interface:接口定义关键字
- 方法签名定义后,直接使用分号(;)结尾,所有都没有方法体
接口的具体规则
- 接口的所有属性与方法,访问修饰符默认都是public
- 接口的所有属性都是公共的静态属性,默认都是public static final修饰的,不可修改
- 接口的所有方法都是公共的抽象方法,默认都是public abstract修饰的,且接口的抽象方法前无需添加abstract修饰符
- 一个接口可以有0~n个抽象方法
- 区别于普通类,接口也是纯抽象的,只能用于被实现,不能使用new关键字进行实例化
- 接口与接口可以相互继承,类则可以实现接口
- 实现接口的的子类,一般需要覆盖接口的所有抽象方法,否则,子类只能是一个抽象类
- 一个类,可以实现多个接口
- 在很多编码规则中,习惯在大驼峰前加一个大写的I,标识是一个接口;但并不是强制要求
- JDK1.8中还引入了static方法和default方法
应用实例,基于上一章的动物示例;思考,是否可以作用一个接口?
应用实例1,定义使用工具接口
package com.bjpowernode.demo;
/**
* 工具
*/
public interface ITool {
/**
* 使用工具
* @param toolName 工具名称
*/
void useTool(String toolName);
}应用实例2,定义安抚接口
package com.bjpowernode.demo;
/**
* 安抚
*/
public interface IAppease {
/**
* 安抚
* @param name 被安抚的人
*/
void appease(String name);
}
使用接口
接口定义好后,可以在需要接口定义行为需要的类中进行实现
使用关键字implements
应用实例,基于上一章的动物示例
实例1,鸟类具有使用工具的行为
鸟类
package com.bjpowernode.demo;
/**
* 鸟类,继承于抽象类动物类Animal,需要覆盖抽象类的所有抽象方法
* 鸟能使用工具,实现了ITool工具类
*/
public class Bird extends Animal implements ITool {
@Override
public void eatFood(String foodName) {
System.out.println("鸟儿" + super.getName() + "一小口一小口吃完了" + foodName);
}
@Override
public void sound() {
System.out.println("鸟儿" + super.getName() + "在叫,叽叽叽...");
}
@Override
public void useTool(String toolName) {
System.out.println("鸟儿" + super.getName() + "使用" + toolName + "填满了瓶子,喝到了水...");
}
}测试代码
package com.bjpowernode.demo;
/**
* 动物测试
*/
public class AnnimalDemo {
public static void main(String[] args) {
//ITool工具类引用
ITool tool;
//鸟类
Bird bird = new Bird();
bird.setName("乌鸦");
//接口ITool的引用,指向子类的对象,实现多态
tool = bird;
tool.userTool("石子");
}
}实例2,海豚具有使用工具、安抚的行为
海豚类
package com.bjpowernode.demo;
/**
* 海豚,继承于抽象类动物类Animal,需要覆盖抽象类的所有抽象方法
* 海豚能使用工具,实现了ITool工具类
* 海豚能安抚自闭小孩,实现了IAppease工具类
*/
public class Dolphin extends Animal implements ITool, IAppease {
@Override
public void eatFood(String foodName) {
System.out.println("海豚" + super.getName() + "一口吞了" + foodName);
}
@Override
public void sound() {
System.out.println("海豚" + super.getName() + "在叫,吱吱吱...");
}
@Override
public void useTool(String toolName) {
System.out.println("海豚" + super.getName() + "使用" + toolName + "进行了表演...");
}
@Override
public void appease(String name) {
System.out.println("海豚" + super.getName() + "安抚了一个emo的小朋友" + name + ",小朋友终于笑起来了...");
}
}测试代码
package com.bjpowernode.demo;
/**
* 动物测试
*/
public class AnnimalDemo {
public static void main(String[] args) {
//ITool工具类引用
ITool tool;
//海豚
Dolphin dolphin = new Dolphin();
dolphin.setName("海豚一号");
//接口ITool的引用,指向子类的对象,实现多态
tool = dolphin;
tool.useTool("皮球");
//接口IAppease的引用,指向子类的对象,实现多态
IAppease appease = dolphin;
appease.appease("张小花");
}
}
【练习】
- 练习应用实例的内容,完成代码编写
接口的作用
- 主要定义简单的通用规范或能力,用于在需要这些能力的类中实现
- 也能弥补类单继承的不足
- 面向接口编程,使得不同项目、不同层次的代码间代码耦合底降低,实现可插拔,实现高可扩展(后续的课程会学习面向接口编程)
接口继承
针对一个已有的接口,除了可以被类实现,也可以被另一个接口继承,但不多见
接口间的继承与类间继承一样,使用extends关键字,接口可以多继承
应用实例,接口间的继承
实例1,人类工具接口继承于工具接口,并使用
工具接口
package com.bjpowernode.demo;
/**
* 工具接口,父接口
*/
public interface ITool {
//工具别称
String ALIAS = "干饭神器";
/**
* 使用工具
*
* @param toolName 工具名称
*/
void useTool(String toolName);
}人类工具接口
package com.bjpowernode.demo;
/**
* 人类工具接口,子接口
*/
public interface IHumanTool extends ITool {
//工具别称
String ALIAS = "生存必备";
/**
* 制作工具
*
* @param toolName 工具名称
*/
void makeTool(String toolName);
/**
* 销毁工具
*
* @param toolName 工具名称
*/
void destroyTool(String toolName);
}人类
package com.bjpowernode.demo;
/**
* 人类,实现IHumanTool接口,如果是普通类,则同时需要实现IHumanTool和ITool中的抽象方法
*/
public class Human implements IHumanTool {
@Override
public void makeTool(String toolName) {
System.out.println("制作了工具[" + toolName + "]");
}
@Override
public void destroyTool(String toolName) {
System.out.println("销毁了工具[" + toolName + "]");
}
@Override
public void useTool(String toolName) {
System.out.println("使用了工具[" + toolName + "]");
}
}人类测试
package com.bjpowernode.demo;
/**
* 人类测试
*/
public class HumanDemo {
public static void main(String[] args) {
//定义对象
Human human = new Human();
//使用方法
human.makeTool("火箭");
human.useTool("火箭");
human.destroyTool("核武器");
//接口静态常量
//可使用【对象.静态常量】访问,使用的是子接口常量,但不推荐,推荐使用【接口.静态常量】
System.out.println("【不推荐】人类使用的工具别称:" + human.ALIAS);
System.out.println("【推荐】人类工具别称:" + IHumanTool.ALIAS);
System.out.println("【推荐】工具别称:" + ITool.ALIAS);
}
}
【练习】
- 练习应用实例的内容,完成代码编写
static方法【扩展】
概述
- 在JDK1.8中,接口引入了static关键字修饰的方法
- static修饰的方法需要有方法体,即有相应的业务逻辑
- 好处
- 提供与接口相关的工具方法,而无需放到单独的工具类中,使得代码更内聚、更合理
- 注意,接口的静态方法只能使用接口.方法调用,一般不能使用子类.方法调用
应用实例
应用实例1、猴子使用工具,并使用static方法
接口,工具接口
package com.bjpowernode.demo.behavior;
/**
* 工具接口
*/
public interface ITool {
/**
* 使用工具
*
* @param toolName 工具名称
*/
void useTool(String toolName);
/**
* 增强工具
*
* @param toolName
* @return
*/
static String enhanceTool(String toolName) {
String enhanceToolName = null;
if (toolName != null) {
enhanceToolName = "超级工具-" + toolName;
}
return enhanceToolName;
}
}猴子,使用工具接口
package com.bjpowernode.demo;
import com.bjpowernode.demo.behavior.ITool;
/**
* 猴子类
*/
public class Monkey extends Animal implements ITool {
@Override
public void eatFood(String foodName) {
System.out.println("猴子" + this.getName() + "大口吃完了" + foodName);
}
@Override
public void sound() {
System.out.println("猴子" + this.getName() + "在叫,呀呀呀...");
}
@Override
public void useTool(String toolName) {
System.out.println("猴子" + this.getName() + "使用[" + toolName + "]砸开了核桃,吃到了果肉...");
}
}猴子测试,使用static方法
package com.bjpowernode.demo;
import com.bjpowernode.demo.behavior.ITool;
public class MonkeyTest {
public static void main(String[] args) {
System.out.println("-------------static方法使用-------------");
Monkey monkey = new Monkey();
monkey.setName("悟空");
ITool tool = monkey;
String toolName = ITool.enhanceTool("石块"); //static方法使用
tool.useTool(toolName);
}
}
【练习】
- 练习应用实例的内容,完成代码编写
default方法【扩展】
概述
- 在JDK1.8中,接口引入了default关键字修饰的方法
- default修饰的方法需要有方法体,即有相应的业务逻辑
- default修饰的方法无需在子类中覆盖
- 另外,由于一个类可以实现多个接口,当实现的多个接口有相同签名的default修饰方法时,需要主动覆盖此方法
- 好处
- 为已有的被广泛使用的接口添加新方法,但不破坏原有接口使用代码的兼容性
- 允许在接口中提供一定的具备默认实现方法,减少实现类强制覆盖抽象方法的负担,类似抽象类中的普通方法模板效果
应用实例
应用实例1,人类使用工具,并使用default方法
接口,工具接口
package com.bjpowernode.demo.behavior;
/**
* 工具接口
*/
public interface ITool {
/**
* 使用工具
*
* @param toolName 工具名称
*/
void useTool(String toolName);
/**
* 重新使用工具,添加一些安全措施
*
* @param toolName
*/
default void reuseTool(String toolName) {
System.out.println("【检查安全帽、安全鞋、手套和防毒面具等防护措施】");
this.useTool(toolName);
}
}人类,使用工具接口
package com.bjpowernode.demo;
import com.bjpowernode.demo.behavior.ITool;
/**
* 人类,实现ITool接口,只需要覆盖其中的抽象方法(不包括default方法)
*/
public class Human implements ITool {
private String name;
@Override
public void useTool(String toolName) {
System.out.println(this.name + "使用[" + toolName + "]完成了工作。");
}
public Human() {
}
public Human(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}人类测试,使用default方法
package com.bjpowernode.demo;
import com.bjpowernode.demo.behavior.ITool;
public class HumanTest {
public static void main(String[] args) {
System.out.println("-------------default方法使用-------------");
Human human = new Human("张三丰");
ITool tool = human;
tool.reuseTool("焊机"); //default方法
}
}
【练习】
- 练习应用实例的内容,完成代码编写
接口与抽象类对比
【注意】:抽象类与接口的应用场景,初学不那么容易理解,在持续学习过程中,会有更深刻的认识,先按照示例应用起来。
实战和作业
提问
下面的代码正确吗?为什么?
package com.bjpowernode.demo;
/**
* 步骤
*/
public interface IStep {
/**
* 第1步
*/
void firstStep();
/**
* 第2步
*/
void secondStep();
/**
* 第3步
*/
void thirdStep();
}package com.bjpowernode.demo;
/**
* 最后一步
*/
public interface ILastStep extends IStep {
/**
* 第4步
*/
void lastStep();
}下面的代码正确吗?为什么?
package com.bjpowernode.demo;
/**
* 步骤
*/
public interface IStep {
/**
* 第1步
*/
void firstStep();
/**
* 第2步
*/
void secondStep();
/**
* 第3步
*/
void thirdStep();
}package com.bjpowernode.demo;
/**
* 我的步骤
*/
public abstract class MyStep implements IStep {
public void firstStep() {
System.out.println("我迈出了学习Java的第1步...");
}
}
完成示例应用,理解接口的使用特点
【扩展】重构程序,在"第12章-抽象类"的animal项目中添加两个Animal的子类,分别为狗类、猫类,要求如下
- 添加的猫类、狗类,继承于Animal类,针对eatFood、sound方法,实现子类自己的逻辑
- 添加陪伴行为(accompany)
- 添加IAccompany接口,具有accompany方法,形式参数为被陪伴的人、陪伴时间,返回为精神饱满度(值为1~100,逻辑可根据陪伴时间自定义)
- 狗类、猫类具备陪伴行为
- 狗类添加本章“定义接口”小节中的使用工具(ITool接口)、安抚(IAppease接口)的行为
- 使用接口ITool的引用指向不同的会使用工具的对象,测试使用工具功能
- 使用接口IAccompany的引用指向不同的会陪伴的对象,测试陪伴功能