接口与抽象类
对比
| 对比项 | 抽象类 | 接口 |
|---|---|---|
| 关键字 | abstract class | interface |
| 继承/实现 | extends,单继承 | implements,可实现多个 |
| 构造器 | 有 | 无 |
| 成员变量 | 任意类型 | 默认 public static final |
| 普通方法 | 有(可有实现) | Java 8+ 支持 default/static |
| 抽象方法 | abstract 修饰 | 默认抽象(Java 8 前全部抽象) |
| 访问修饰符 | 无限制 | 方法默认 public |
| 适用场景 | is-a 关系,共享状态与实现 | can-do 关系,定义能力契约 |
抽象类
用 abstract 修饰,不能实例化,可以有抽象方法也可以全是具体方法。
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象方法:子类必须实现
public abstract double area();
// 具体方法:子类可直接继承
public void describe() {
System.out.println("颜色: " + color + ", 面积: " + area());
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}使用场景:多个类有共同状态(字段)和部分共享逻辑,同时有不同的具体行为。
接口
public interface Flyable {
// 常量(隐式 public static final)
int MAX_HEIGHT = 10000;
// 抽象方法(隐式 public abstract)
void fly();
// Java 8:default 方法(有默认实现,子类可选择重写)
default void land() {
System.out.println("正在降落");
}
// Java 8:static 方法
static Flyable of(String type) {
return () -> System.out.println(type + " is flying");
}
// Java 9:private 方法(供 default 方法复用,不对外暴露)
private void logFlight(String msg) {
System.out.println("[LOG] " + msg);
}
}
// 实现多个接口
public class Eagle extends Bird implements Flyable, Huntable {
@Override
public void fly() { System.out.println("老鹰飞翔"); }
@Override
public void hunt() { System.out.println("老鹰捕猎"); }
}接口默认方法冲突
一个类实现多个接口且都有同名 default 方法时,必须显式重写:
interface A {
default void hello() { System.out.println("A"); }
}
interface B {
default void hello() { System.out.println("B"); }
}
class C implements A, B {
@Override
public void hello() {
A.super.hello(); // 显式选择调用 A 的实现
}
}函数式接口
只含一个抽象方法的接口,可用 @FunctionalInterface 标注,支持 Lambda 表达式。
@FunctionalInterface
public interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> toInt = Integer::parseInt;
System.out.println(toInt.convert("123")); // 123JDK 内置常用函数式接口(java.util.function):
| 接口 | 参数 | 返回 | 说明 |
|---|---|---|---|
Supplier<T> | 无 | T | 提供值 |
Consumer<T> | T | void | 消费值 |
Function<T,R> | T | R | 转换 |
Predicate<T> | T | boolean | 判断 |
BiFunction<T,U,R> | T, U | R | 双参数转换 |
UnaryOperator<T> | T | T | 同类型转换 |
选择指南
需要共享字段状态? → 抽象类
需要多继承能力? → 接口
is-a 语义(狗是动物)? → 抽象类
can-do 语义(鸟能飞)? → 接口
定义回调 / 策略? → 函数式接口
接口 vs 抽象类 演进
Java 8 之前接口只能有抽象方法,导致接口升级(新增方法)会破坏所有实现类。default 方法的引入解决了向后兼容问题,使接口能在不破坏现有实现的前提下扩展功能。