今天我们聊聊java基础知识中的接口,接口这个名字听起来有些抽象,没错接口其实就是抽象的,大家这时候就有疑问了,抽象类不能用么,为什么又出现一个接口的概念,让人真的觉得繁杂,前几篇我给大家说过,任何一项新技术的产生都是为了方便简单的实现某种目的。
那么说这么多还是没明白接口是干啥的呀,接口其实将实现功能范围扩大了,比如马儿会跑,汽车也会跑,跑这个动作是不同种类之间实现的,比如马儿是动物大类中的,汽车是机械大类中的,汽车和马儿都不在同种大类范围下,那么抽象类范围小点相当于同种类中不同对象对方法的不同实现,比如动物类下小猫小狗都实现跑这个动作。
抽象类类比:
接口类比:
从上边两个图片可以看出,其实接口的出现就是将类的实现范围扩大了,那么大家思考个问题,接口能像普通类一样实现接口之间的继承吗?答案是可以的,但是接口不是类,类只能实现单继承,而接口可以实现多继承。
接口间的继承
假设我们有一家公司,公司有DevOps (运维)、Tester (测试)、Developer (开发)和ProductManager (产品经理)。
然后,我们让ProductManager (产品经理)接口继承DevOps 、Tester 和Developer三个接口,形成多继承。
DevOps(运维)接口:
csharp
public interface DevOps {
void deployApp(); // 部署应用
default void handleIncidents() { // 处理事故
System.out.println("运维人员处理事故...");
}
}
Tester(测试)接口:
csharp
public interface Tester {
void exeTests(); // 执行测试
default void reportBugs() { // 报告缺陷
System.out.println("测试人员报告系统缺陷...");
}
}
Developer(开发)接口:
csharp
public interface Developer {
void writeCode(); // 编写代码
default void refCode() { // 重构代码
System.out.println("开发人员重构代码...");
}
}
ProductManager(产品经理)接口:
csharp
public interface ProductManager extends DevOps, Tester, Developer{
void gatherRequirements(); // 收集需求
// 默认方法 - 协调不同团队
default void coordTeams() {
System.out.println("产品经理协调开发、运维、测试...");
}
}
我们会发现ProductManager (产品经理)接口继承了三个父接口,DevOps (运维)、Tester (测试)、Developer (开发),说明产品经理三个父接口的6个方法还有自己的一个抽象方法和一个默认方法,那么产品经理就有8个方法,这个时候还不能直接的使用接口中的方法,需要有实现类来实现产品经理这个接口,通过实现类创建相关类对象并对接口的抽象方法进行重写,这时候接口中的默认方法和重写的方法就可以被调用了,其实接口中定义的方法就像一颗子弹,没有枪是无法发挥其本身的威力的,那么接口的实现类就是子弹的发射器,就是枪。
接口的实现
我们让TechManager (技术总监)去实现ProductManager(产品经理)的这个接口。
typescript
public class TechManager implements ProductManager{
private String name;
public TechManager(String name) {
this.name = name;
}
// 实现ProductManager接口的方法
@Override
public void gatherRequirements() {
System.out.println(name + " 产品经理收集需求抽象方法重写.");
}
// 实现DevOps接口的方法
@Override
public void deployApp() {
System.out.println(name + " 运维部署应用抽象方法重写.");
}
// 实现Tester接口的方法
@Override
public void exeTests() {
System.out.println(name + " 测试抽象方法重写.");
}
// 实现Developer接口的方法
@Override
public void writeCode() {
System.out.println(name + " 开发写代码抽象方法重写.");
}
// 重写默认方法以提供特定实现
@Override
public void coordTeams() {
System.out.println(name + " 技术总监重写产品经理协调团队默认方法 .");
}
}
测试代码:
csharp
public class StartDemo {
public static void main(String[] args) {
// 创建技术总监实例
TechManager pm = new TechManager("Tom");
System.out.println("=== 产品经理职责 ===");
pm.gatherRequirements();
pm.coordTeams();
System.out.println("=== 运维技能 ===");
pm.deployApp();
pm.handleIncidents(); // 使用继承的默认方法
System.out.println("=== 测试技能 ===");
pm.exeTests();
pm.reportBugs(); // 使用继承的默认方法
System.out.println("=== 开发技能 ===");
pm.writeCode();
pm.refCode(); // 使用继承的默认方法
}
}
测试代码运行效果:
我们看到实现类实现了产品经理的接口,而产品经理接口继承了3个接口的所有方法,则TechManager (技术总监)这个类要重写DevOps (运维)、Tester (测试)、Developer (开发)ProductManager (产品经理)的所有抽象方法,那么接口中有了抽象方法还要默认方法干啥?接口中默认方法是为了如果有多个实现类中有相同的行为,那么避免重复在实现类中写出冗余方法,这个就是类去实现接口的意义,如果这个类不想重写接口中的抽象方法的话,这个类也只能以抽象类的形式存在,看到这的朋友们是不是在接口中没有看到属性?其实接口中的属性可以理解为不可更改常量,这个通常以 " public static final int x = 1"的形式存在,这样定义避免了多继承中属性的不确定性,这个接口常量相当于全局统一。
接口与抽象类
在实际应用中我们应该如何在接口和抽象类中进行选型:
其实大部分实际的应用中都是接口和抽象类组合使用,这样可以提高代码的灵活性和复用性,组合使用使得代码既有统一契约又有共享实现的特点,接下来我们看看接口和抽象类组合的例子,加深一下对接口和抽象类组合的理解深度。
我们有一个接口Switchable ,一个实现接口的抽象类AbstractSwitch ,一个具体类Light 继承抽象类去实现具体的行为。
Switchable接口:
csharp
public interface Switchable {
void turnOn();
void turnOff();
boolean status();
}
AbstractSwitch抽象类:
typescript
public abstract class AbstractSwitch implements Switchable{
protected boolean status = false;
@Override
public void turnOn() {
status = true;
System.out.println("设备开启...");
}
@Override
public void turnOff() {
status = false;
System.out.println("设备关闭...");
}
@Override
public boolean status() {
return status;
}
// 抽象方法 - 由子类实现具体行为
protected abstract void deviceAction();
}
Light具体类:
typescript
public class Light extends AbstractSwitch {
@Override
protected void deviceAction() {
if (status()) {
System.out.println("设备灯亮...");
} else {
System.out.println("设备灯关闭...");
}
}
@Override
public void turnOn() {
super.turnOn();
deviceAction();
}
@Override
public void turnOff() {
super.turnOff();
deviceAction();
}
}
测试代码:
typescript
public class StartDemo1 {
public static void main(String[] args) {
Switchable light = new Light();
light.turnOn();
light.turnOff();
}
}
运行测试代码的效果:
从上面我们可以看出接口Switchable 定义了设备应该具备的基本操作(契约),抽象类AbstractSwitch 实现了接口Switchable 并对接口Switchable 中的抽象方法进行了重写,AbstractSwitch 提供了开关状态的通用实现,但留下了 deviceAction()
方法待具体实现,具体类对deviceAction()
进行了重写实现具体功能。
好了,接口部分的知识就给大家分享的到这里了,谢谢大家的观看与支持,下期我们再见。