接口是契约
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