Skip to content

接口:定义「能做什么」

想象这样一个场景:你要写一个排序算法,但不确定要排序什么类型——可能是整数、字符串,甚至是自定义对象。怎么办?

你需要一个抽象合约,而不是具体实现。这就是接口的价值所在。

接口是什么

接口(Interface)是 Java 中的行为契约。它只告诉你「能做什么」,不关心「怎么做」。

java
public interface Flyable {
    void fly();
}

这个接口说的是:任何声称自己是 Flyable 的东西,必须会飞。至于鸟、飞机、超人怎么飞,由它们自己决定。

定义接口

java
public interface 接口名 {
    // 常量(默认 public static final)
    int MAX_SPEED = 100;

    // 抽象方法(默认 public abstract)
    void method1();

    // JDK 8+ 默认方法
    default void defaultMethod() {
        System.out.println("默认实现");
    }

    // JDK 8+ 静态方法
    static void staticMethod() {
        System.out.println("静态方法");
    }

    // JDK 9+ 私有方法
    private void helper() {
        System.out.println("私有辅助");
    }
}

接口的字段默认是 public static final,所以这些本质上都是常量

实现接口

类通过 implements 关键字声明它要遵守某个契约:

java
public class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("鸟儿扇翅膀飞翔");
    }
}

使用时的多态体现:

java
Flyable f = new Bird();
f.fly();  // 鸟儿扇翅膀飞翔

多接口实现

一个类可以实现多个接口,这是 Java 实现「多继承」的方式:

java
public interface Runnable {
    void run();
}

public interface Swimmable {
    void swim();
}

// Duck 同时是运动员和水上运动选手
public class Duck implements Runnable, Swimmable {
    @Override
    public void run() {
        System.out.println("鸭子奔跑");
    }

    @Override
    public void swim() {
        System.out.println("鸭子游泳");
    }
}

接口 vs 抽象类

对比项接口抽象类
继承多实现单继承
方法只能是抽象方法(JDK 7 前)抽象 + 普通都可以
字段只能是常量无限制
构造方法不能有可以有
使用场景「能做什么」(can-do)「是什么」(is-a)

选择原则:如果你在说「X 是什么」,用抽象类;如果在说「X 能做什么」,用接口。

常用接口示例

Comparable:可排序

java
public class User implements Comparable<User> {
    private String name;
    private int age;

    @Override
    public int compareTo(User other) {
        // 按年龄排序,返回负数表示小于
        return this.age - other.age;
    }
}

// 使用
List<User> users = new ArrayList<>();
Collections.sort(users);  // 自动按年龄排序

Comparator:自定义排序

java
List<String> names = Arrays.asList("Tom", "Alice", "Bob");

// 按长度排序
names.sort(Comparator.comparingInt(String::length));

// 先按长度,再按字母序
names.sort(Comparator
    .comparingInt(String::length)
    .thenComparing(Comparator.naturalOrder()));

Cloneable:可复制

java
public class MyClass implements Cloneable {
    @Override
    protected MyClass clone() throws CloneNotSupportedException {
        return (MyClass) super.clone();
    }
}

函数式接口

只有一个抽象方法的接口称为函数式接口,可以用 Lambda 表达式实现:

java
@FunctionalInterface
public interface Converter<F, T> {
    T convert(F from);
}

// 使用 Lambda
Converter<String, Integer> toInt = Integer::parseInt;
Integer result = toInt.convert("123");  // 123

JDK 内置的常用函数式接口:

接口抽象方法说明
Runnablevoid run()无参数无返回值
Supplier<T>T get()无参数有返回值
Consumer<T>void accept(T t)消费参数,无返回值
Function<T,R>R apply(T t)转换,有参数有返回值
Predicate<T>boolean test(T t)判断,返回布尔值

实战:策略模式

接口最经典的应用之一是策略模式:

java
// 定义支付策略
interface PaymentStrategy {
    void pay(double amount);
}

// 支付宝策略
class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount);
    }
}

// 微信支付策略
class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount);
    }
}

// 订单使用策略
class Order {
    private PaymentStrategy strategy;

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void checkout(double amount) {
        strategy.pay(amount);
    }
}

// 使用
Order order = new Order();
order.setStrategy(new AlipayStrategy());
order.checkout(100);

这样添加新的支付方式只需要新增一个类,不需要修改 Order 的代码。

总结

接口 = 行为契约
类   = 签署契约

implements → 「我承诺能做这些」

接口让程序变得可插拔可扩展易测试。这是面向对象设计中最重要的思想之一。

基于 VitePress 构建