接口:定义「能做什么」
想象这样一个场景:你要写一个排序算法,但不确定要排序什么类型——可能是整数、字符串,甚至是自定义对象。怎么办?
你需要一个抽象合约,而不是具体实现。这就是接口的价值所在。
接口是什么
接口(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"); // 123JDK 内置的常用函数式接口:
| 接口 | 抽象方法 | 说明 |
|---|---|---|
Runnable | void 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 → 「我承诺能做这些」接口让程序变得可插拔、可扩展、易测试。这是面向对象设计中最重要的思想之一。
