接口是契约

public interface Repository<T> {
    Optional<T> findById(long id);
    List<T> findAll();
    void save(T item);
    void delete(long id);
}

public class UserRepository implements Repository<User> {
    @Override
    public Optional<User> findById(long id) { ... }
    @Override
    public List<User> findAll() { ... }
    @Override
    public void save(User u) { ... }
    @Override
    public void delete(long id) { ... }
}

implements 关键字。可实现多个接口:

public class C implements A, B, X { ... }

接口的成员

public interface MyInterface {
    // 抽象方法(默认 public abstract)
    void doSomething();

    // 默认方法(Java 8+)
    default String prefix() {
        return "[Default] ";
    }

    // 静态方法(Java 8+)
    static MyInterface empty() {
        return new MyInterface() { public void doSomething() {} };
    }

    // 私有方法(Java 9+,给默认方法复用)
    private String format(String s) {
        return "[" + s + "]";
    }

    // 常量(默认 public static final)
    int MAX = 100;
}

接口可以有:

  • 抽象方法(必须实现)
  • 默认方法(可选重写)
  • 静态方法(直接 MyInterface.xxx() 调)
  • 私有方法(仅同接口内)
  • 常量(public static final,全大写)

不能有实例字段(构造也不能)。

default method 解决"扩展接口"

public interface List<T> {
    int size();
    boolean isEmpty();          // 旧版抽象
}

// 后来想加 stream() 怎么办?
// 加抽象方法 → 所有实现类都得改 → 破坏向后兼容

// Java 8 解法:默认方法
public interface List<T> {
    int size();
    default boolean isEmpty() {
        return size() == 0;     // 给个默认实现
    }
    default Stream<T> stream() {
        return ...;
    }
}

旧的实现类不写 isEmpty / stream 也能跑。

多接口冲突

interface A { default void hi() { System.out.println("A"); } }
interface B { default void hi() { System.out.println("B"); } }

public class C implements A, B {
    @Override
    public void hi() {
        A.super.hi();      // 显式调 A 的版本
        B.super.hi();      // 显式调 B 的版本
    }
}

接口冲突时必须显式 override——不会自动选一个。

函数式接口(Functional Interface)

只有一个抽象方法的接口 = 函数式接口,能用 lambda 实现:

@FunctionalInterface
public interface Greeter {
    String greet(String name);
}

// Lambda 实现
Greeter g = name -> "Hello, " + name;
System.out.println(g.greet("Alice"));   // Hello, Alice

@FunctionalInterface 不强制——编译器自动识别。加上让代码更清晰、并阻止意外加第二个抽象方法。

详见 第 18 篇

JDK 内置函数式接口

接口 方法 用途
Function<T, R> R apply(T) 转换
Predicate<T> boolean test(T) 判断
Consumer<T> void accept(T) 消费
Supplier<T> T get() 供给
BiFunction<T, U, R> R apply(T, U) 两参转换
Runnable void run() 无参无返
Function<Integer, Integer> doubled = x -> x * 2;
Predicate<String> notEmpty = s -> !s.isEmpty();
Consumer<String> print = System.out::println;
Supplier<LocalDate> today = LocalDate::now;

标记接口(marker interface)

public interface Serializable {}    // 没成员

仅用作"打标记"。Serializable / Cloneable 是历史经典。

现代写法:用 annotation 更清晰:

@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {}

@Cacheable
public class User { ... }

新代码极少手写标记接口。

常用 JDK 接口

接口 用途
Iterable<T> 能 foreach
Comparable<T> 可比较(自然顺序)
Comparator<T> 外部比较器
Iterator<T> 迭代器
AutoCloseable try-with-resources
Runnable / Callable<V> 线程任务
Cloneable 支持 clone(争议大,少用)
Serializable 序列化(也有争议)

SOLID 中的 I

接口隔离原则:

// ❌ 大接口
public interface Worker {
    void eat();
    void sleep();
    void code();
    void refactor();
    void deployToProd();
}

// ✅ 小接口
public interface Eater { void eat(); }
public interface Sleeper { void sleep(); }
public interface Coder { void code(); }

按需组合接口——比强迫实现不需要的方法好。

接口 vs 抽象类决策

场景
多种实现,纯契约 接口
共享状态 / 字段 抽象类
大量共享逻辑 + 部分扩展 抽象类
不确定 接口先(更灵活)

接口能加 default 方法后,接口能干 80% 的事情——抽象类用得越来越少。

record 实现接口

public interface Greeter {
    String greet();
}

public record Person(String name) implements Greeter {
    @Override
    public String greet() {
        return "Hi, " + name;
    }
}

record 自带 toString / equals 等,还能实现接口——非常实用。

→ 下一篇 record + sealed