《Java数据结构与算法》特别篇:Java接口详解:高效入门、应用场景、与继承的关系及多态特性
目录
前言
在我们学习“队列”这种数据结构,并准备用它实现具体功能时,“接口”的概念将至关重要。因此,在深入代码之前,我认为有必要先写一篇文章,专门探讨接口如何定义规范并提升程序的灵活性。
正文
一、接口快速入门以及应用场景
1.1 为什么需要接口
接口的出现是为了解决Java单继承的局限性,让类具有更多的扩展能力。在实际编程中,我们经常遇到这样的情况:多个不相关的类需要具有相似的行为,但这些类已经存在于不同的继承体系中。
应用场景举例:
不同设备(手机、电脑、相机)都需要充电功能
不同支付方式(支付宝、微信、银行卡)都需要支付功能
不同交通工具(汽车、飞机、轮船)都需要移动功能
1.2 接口快速入门
// 接口定义
interface UsbInterface {
// 定义抽象方法
public void start();
public void stop();
}
// 实现接口
class Camera implements UsbInterface {
public void start() {
System.out.println("相机开始工作...");
}
public void stop() {
System.out.println("相机停止工作...");
}
}
class Phone implements UsbInterface {
public void start() {
System.out.println("手机开始工作...");
}
public void stop() {
System.out.println("手机停止工作...");
}
}
// 测试类
public class InterfaceDemo {
public static void main(String[] args) {
Camera camera = new Camera();
Phone phone = new Phone();
// 接口的多态体现
UsbInterface[] usbDevices = {camera, phone};
for (UsbInterface device : usbDevices) {
device.start();
device.stop();
System.out.println("------");
}
}
}
二、接口小常识
2.1 接口的基本语法
// 接口定义
[public] interface 接口名 {
// 属性(常量)
[public] [static] [final] 数据类型 属性名 = 值;
// 方法(抽象方法)
[public] [abstract] 返回值类型 方法名(参数列表);
// 默认方法(JDK8+)
default 返回值类型 方法名(参数列表) {方法体}
// 静态方法(JDK8+)
static 返回值类型 方法名(参数列表) {方法体}
}
2.2 接口的注意事项和细节
接口不能被实例化
接口中所有方法都是public方法,接口中的抽象方法可以不用abstract修饰
一个普通类实现接口,必须实现该接口的所有方法
抽象类实现接口,可以不用实现接口的方法
一个类可以同时实现多个接口
接口中的属性只能是final的,而且是public static final修饰符
接口中属性的访问形式:接口名.属性名
接口不能继承其他的类,但可以继承多个别的接口
接口的修饰符只能是public和默认,这点和类的修饰符是一样的
2.3 接口vs抽象类
特性 | 抽象类 | 接口 |
|---|---|---|
继承 | 单继承 | 多实现 |
方法 | 可以有具体方法 | JDK8前只能有抽象方法 |
构造器 | 有构造器 | 没有构造器 |
属性 | 可以是各种类型 | 只能是常量 |
设计理念 | is-a关系 | has-a关系 |
三、接口与继承
3.1 接口与继承的多态
接口的多态性主要体现在:接口类型的引用可以指向实现了该接口的类的对象。
interface A {
void methodA();
}
interface B {
void methodB();
}
class C implements A, B {
public void methodA() {
System.out.println("实现methodA");
}
public void methodB() {
System.out.println("实现methodB");
}
public void methodC() {
System.out.println("C类特有方法");
}
}
public class InterfacePolymorphism {
public static void main(String[] args) {
// 接口的多态体现
A a = new C(); // 向上转型
a.methodA();
// a.methodB(); // 错误,A接口没有methodB方法
// a.methodC(); // 错误,A接口没有methodC方法
B b = new C(); // 向上转型
b.methodB();
// 运行类型是C,可以调用所有方法
C c = new C();
c.methodA();
c.methodB();
c.methodC();
// 向下转型
if (a instanceof C) {
C c2 = (C)a;
c2.methodC();
}
}
}
3.2 接口多态传递
接口多态传递是指:如果一个接口继承了另一个接口,那么实现类需要实现所有父接口的方法。
// 接口的多态传递现象
interface IA {
void methodA();
}
interface IB extends IA { // 接口继承接口
void methodB();
}
class MyClass implements IB {
// 必须实现IA和IB的所有方法
public void methodA() {
System.out.println("实现methodA");
}
public void methodB() {
System.out.println("实现methodB");
}
}
public class InterfaceInheritance {
public static void main(String[] args) {
// 多态传递的体现
IA ia = new MyClass(); // MyClass实现了IB,而IB继承了IA
ia.methodA();
IB ib = new MyClass();
ib.methodA(); // 可以调用父接口的方法
ib.methodB();
// 多态数组
IA[] arrays = new IA[2];
arrays[0] = new MyClass();
arrays[1] = new MyClass();
for (IA item : arrays) {
item.methodA();
}
}
}
3.3 接口多态的实际应用:多态参数和多态数组
// 实际应用案例
interface Employee {
double calculateSalary();
String getInfo();
}
class Manager implements Employee {
private String name;
private double baseSalary;
private double bonus;
public Manager(String name, double baseSalary, double bonus) {
this.name = name;
this.baseSalary = baseSalary;
this.bonus = bonus;
}
public double calculateSalary() {
return baseSalary + bonus;
}
public String getInfo() {
return "经理:" + name + ",薪资:" + calculateSalary();
}
}
class Programmer implements Employee {
private String name;
private double dailyWage;
private int workDays;
public Programmer(String name, double dailyWage, int workDays) {
this.name = name;
this.dailyWage = dailyWage;
this.workDays = workDays;
}
public double calculateSalary() {
return dailyWage * workDays;
}
public String getInfo() {
return "程序员:" + name + ",薪资:" + calculateSalary();
}
}
public class CompanySystem {
// 多态参数:可以接收任何实现了Employee接口的对象
public static void showEmployeeInfo(Employee emp) {
System.out.println(emp.getInfo());
}
// 多态数组:可以存储不同类型的员工
public static double getTotalSalary(Employee[] employees) {
double total = 0;
for (Employee emp : employees) {
total += emp.calculateSalary();
}
return total;
}
public static void main(String[] args) {
Employee[] employees = new Employee[3];
employees[0] = new Manager("张三", 10000, 5000);
employees[1] = new Programmer("李四", 500, 22);
employees[2] = new Manager("王五", 12000, 6000);
// 遍历多态数组
for (Employee emp : employees) {
showEmployeeInfo(emp); // 多态参数
}
System.out.println("总薪资:" + getTotalSalary(employees));
}
}
运行结果:
四、接口多态传递的深入理解
小问题:如果有这样的代码,会出现什么错误
interface A {
int x = 0;
}
class B {
int x = 1;
}
class D extends B implements A {
public void pX() {
System.out.println(x);
}
public static void main(String[] args) {
new D().pX();
}
}
错误抛出:
这是一个很有意思的例子,只需要改一下代码就行
interface A {
int x = 0;
}
class B {
int x = 1;
}
class D extends B implements A {
public void pX() {
System.out.println(A.x + " " + super.x);
}
public static void main(String[] args) {
new D().pX();
}
}
现在的输出结果就准确了
接口多态传递的核心思想是:面向接口编程,而不是面向实现编程。这种设计模式让代码更加灵活、可扩展和可维护。
设计原则体现:
开闭原则:对扩展开放,对修改关闭
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖抽象
接口隔离原则:使用多个专门的接口,而不是一个庞大的总接口
通过接口的多态特性,我们可以构建出松耦合、高内聚的系统架构,这也是Java面向对象编程的精髓所在。
总结
接口作为Java面向对象编程的重要组成部分,提供了强大的抽象能力和多态支持。通过接口,我们可以:
定义规范:为不同的实现类制定统一的操作标准
实现多态:提高代码的灵活性和可扩展性
突破单继承限制:让类具有更多的行为特征
降低耦合度:使系统各模块之间松耦合,易于维护和扩展
在实际开发中,特别是在设计数据结构和算法时(如队列、栈等),接口的使用能够让我们的代码更加优雅和健壮。当我们学习队列时,通过定义队列接口,可以让数组队列和链表队列实现相同的操作方法,从而在使用时无需关心具体实现细节。
致谢
感谢您阅读这篇关于Java接口的详细介绍。希望通过本文的学习,您能够深入理解接口的概念、特性和应用场景,并在实际编程中灵活运用接口来提升代码质量。接口作为Java编程的重要基石,掌握好它将为您的编程之路打下坚实基础。
如果您在学习过程中有任何疑问或建议,欢迎交流讨论。编程之路,我们一起进步!
浙公网安备 33010602011771号