Java 接口
Java - 接口
Section titled “Java - 接口”在 Java 中,interface(接口)是一种引用类型,类似于 class(类),它定义了一种契约。它指定了一组实现类必须提供的 abstract method(抽象方法)。从 Java 8 开始,接口还可以包含 default method(默认方法)、static method(静态方法),甚至 private method(私有方法,从 Java 9 开始)。
可以将 interface 视为功能的一种蓝图。class 通过 implements(实现)一个接口,承诺提供该接口契约中定义的功能。
Java 接口的主要特性:
Section titled “Java 接口的主要特性:”- 不能直接实例化。
- 可以包含
abstract method(抽象方法,没有实现,隐式为public abstract)。 - 可以包含
default method(默认方法,Java 8 引入):提供一个实现类可以直接继承的默认实现。这允许在接口中添加新方法,而不会破坏现有的实现。 - 可以包含
static method(静态方法,Java 8 引入):与接口本身关联的工具方法,不与任何实现对象关联。 - 可以包含
private method(私有方法,Java 9 引入):接口内部默认方法或静态方法的辅助方法。 - 可以包含
public static final常量(字段)。所有字段隐式都是public、static和final的。 - 一个类可以实现多个接口。
- 一个接口可以继承(
extends)多个其他接口。
为何使用接口?
Section titled “为何使用接口?”- 实现抽象:隐藏实现细节,仅暴露必要行为。
- 实现类型的多重继承:一个类可以实现多个接口,继承不同的功能集合。
- 实现松耦合:代码依赖于接口契约,而不是具体的实现,使系统更灵活且易于维护。
- 实现多态:对象可以被视为其实现的接口类型的实例。
- 定义 API:为库和框架定义清晰的契约。
使用 interface 关键字来声明接口。文件名必须与接口名匹配(例如,Vehicle.java)。
现代接口示例:
Section titled “现代接口示例:”/* 文件名: Vehicle.java */
/** * 定义车辆的基本功能。 */public interface Vehicle {
// 常量(隐式为 public static final) String TYPE = "Generic Vehicle";
// 抽象方法(隐式为 public abstract) void startEngine();
void stopEngine();
// 默认方法(Java 8+) default void honk() { System.out.println("Beep beep!"); log("Honk executed"); // 使用私有辅助方法 }
// 静态方法(Java 8+) static void displayType() { System.out.println("This is a type of: " + TYPE); }
// 私有方法(Java 9+)- 默认方法/静态方法的辅助方法 private void log(String message) { System.out.println("LOG: " + message); }}一个类使用 implements 关键字来实现一个或多个接口。如果一个类实现了一个接口但没有为所有抽象方法提供实现,则该类本身必须被声明为 abstract(抽象类)。
在实现接口方法时使用 @Override 注解,以便进行编译时检查和提高代码清晰度。
public class Car implements Vehicle {
private boolean engineRunning = false;
@Override public void startEngine() { engineRunning = true; System.out.println("Car engine started."); }
@Override public void stopEngine() { engineRunning = false; System.out.println("Car engine stopped."); }
// 可选:重写默认方法 @Override public void honk() { System.out.println("HONK HONK! (Car specific)"); }
public boolean isEngineRunning() { return engineRunning; }
public static void main(String[] args) { // 使用接口中的静态方法 Vehicle.displayType();
Car myCar = new Car(); myCar.startEngine(); myCar.honk(); // 调用被重写的 honk 方法 myCar.stopEngine();
// 多态:将 Car 视为 Vehicle 类型 Vehicle anotherVehicle = new Car(); anotherVehicle.startEngine(); // 错误:isEngineRunning() 方法不在 Vehicle 接口中 // anotherVehicle.isEngineRunning();
// 如果没有重写 honk,则使用默认 honk 的示例 Vehicle bike = new Motorbike(); // 假设 Motorbike 类实现了 Vehicle 接口但没有重写 honk 方法 bike.startEngine(); bike.honk(); // 调用 Vehicle 接口中的默认 honk() 方法 bike.stopEngine(); }}
// 假设 Motorbike 类存在,并实现了 Vehicle 接口但没有重写 honk/*class Motorbike implements Vehicle { @Override public void startEngine() { System.out.println("Motorbike engine started."); } @Override public void stopEngine() { System.out.println("Motorbike engine stopped."); }}*/实现的关键规则:
Section titled “实现的关键规则:”- 类必须实现其所实现接口中定义的所有抽象方法,否则该类必须声明为
abstract(抽象类)。 - 实现方法必须具有相同的签名(名称、参数类型)和兼容的返回类型(相同或子类型)。
- 实现方法不能具有更严格的访问修饰符(例如,如果接口方法是
public,则实现也必须是public)。 - 使用
@Override注解。 - 一个类可以通过在
implements关键字后列出多个接口(用逗号分隔)来同时实现多个接口(例如,class MyClass implements InterfaceA, InterfaceB)。
一个接口可以使用 extends 关键字继承(扩展)其他接口。这允许创建接口的层次结构。子接口继承其父接口的所有抽象方法、默认方法、静态方法和常量。
示例:继承接口
Section titled “示例:继承接口”public interface ElectricVehicle extends Vehicle { // 继承 Vehicle void charge(); int getBatteryLevel();}
// 文件名: Autonomous.javapublic interface Autonomous { void driveAutonomously();}
// 文件名: AutonomousElectricCar.java// 实现类需要实现来自 ElectricVehicle、Vehicle 和 Autonomous 的方法public class AutonomousElectricCar implements ElectricVehicle, Autonomous {
@Override public void startEngine() { /* 实现 */ System.out.println("Electric motor started."); }
@Override public void stopEngine() { /* 实现 */ System.out.println("Electric motor stopped."); }
@Override public void charge() { /* 实现 */ System.out.println("Charging..."); }
@Override public int getBatteryLevel() { /* 实现 */ return 85; }
@Override public void driveAutonomously() { /* 实现 */ System.out.println("Driving autonomously."); }
// 它仍然可以使用来自 Vehicle 的默认/静态方法,例如 honk()}接口对比抽象类
Section titled “接口对比抽象类”随着默认方法的加入,接口也可以提供实现了,这使得接口与抽象类之间的界限变得模糊。然而,关键区别依然存在:
- 多重继承: 一个类可以实现多个接口,但只能继承一个抽象类。
- 状态(实例变量): 抽象类可以有实例变量(状态),而传统上接口不能(只能有
public static final常量)。 - 构造方法: 抽象类可以有构造方法,接口不能。
- 用途: 当你想要为一组相关的子类提供通用的基础实现和状态时,使用抽象类(一种 “is-a” 关系)。当你想要定义一个可以由各种可能不相关的类实现(提供)的契约或能力时,使用接口(一种 “has-a” 或 “can-do” 关系)。
函数式接口是只包含一个抽象方法的接口(但可以包含多个默认方法或静态方法)。它们对于在 Java 中使用 lambda expression(Lambda 表达式)和 method reference(方法引用)实现函数式编程至关重要(例如 Runnable、Comparator、ActionListener)。
可以使用 @FunctionalInterface 注解来表明这种意图,并让编译器进行验证。
@FunctionalInterfaceinterface MyFunctionalInterface { void execute(); // 单个抽象方法
default void print() { System.out.println("Printing from functional interface."); }}
// Lambda 用法:MyFunctionalInterface runner = () -> System.out.println("Executing lambda.");runner.execute(); // 输出:Executing lambda.runner.print(); // 输出:Printing from functional interface.进一步学习:
Section titled “进一步学习:”查阅 Java 文档,了解 List、Map、Set、Comparable、Runnable 和 Callable 等核心接口,以查看实际示例。