接口声明一个契约——一组类型必须提供的方法——很少或没有实现。抽象类是一个部分实现的类,可以保有共享状态和具体方法,但不能被实例化。关键区别:一个类可以实现多个接口,但只能继承自一个类。
| 接口 | 抽象类 |
|---|
| 可实例化 | 否 | 否 |
| 多重继承 | 是(实现多个) | 否(单一基类) |
| 字段/状态 | 否(仅常量) | 是 |
| 方法体 | 仅默认方法* | 是,完全实现 |
| 建模方式 | 一种能力("能做什么") | 一种是什么关系(带共享代码) |
*现代 Java 允许 default 方法和常量;精神仍然如此。
interface Drawable { // a capability
void draw();
}
abstract class Shape { // shared identity + state
protected String color;
Shape(String color) { this.color = color; }
abstract double area(); // subclasses must define
String describe() { // shared concrete behavior
return color + " shape, area=" + area();
}
}
class Circle extends Shape implements Drawable {
private double r;
Circle(String c, double r) { super(c); this.r = r; }
double area() { return Math.PI * r * r; }
public void draw() { /* render */ }
}
Circle 是一个 Shape(一个基类,共享代码)且可以是 Drawable(混入的能力)。
选择错误会锁定你的设计:抽象基类强制采用单一继承链,而接口让类型可以自由组合能力。
接口是解耦的首选方案——依赖于契约而非具体的类层次结构,能够保持代码的可测试性和可扩展性。