第一部分:接口 vs 抽象类总览
通过表格快速了解核心区别与联系
学习目标
掌握接口与抽象类的核心区别,能在实际开发中正确选择
对比维度 | 接口 (Interface) | 抽象类 (Abstract Class) |
---|---|---|
关键字 | interface |
abstract class |
继承方式 | implements | extends |
多继承 | 支持多实现 | 单继承 |
构造方法 | ❌ 无构造方法 | ✅ 可以有构造方法 |
默认实现 | Java 8+ 支持 default 方法 | 可以有具体方法 |
成员变量 | 只能是 public static final | 任意类型变量 |
访问修饰符 | 默认 public | 支持任意修饰符 |
使用场景 | 定义能力/规范 | 代码复用与模板方法 |
第二部分:接口深入理解
从 Java 7 到 Java 17 接口的演进
1
经典接口定义
Java 7 及之前的接口只能包含常量和抽象方法:
public interface Drawable {
// 默认就是 public static final
int MAX_SIZE = 100;
// 抽象方法,默认 public abstract
void draw();
double calculateArea();
}
2
Java 8+ 接口增强
支持 default 和 static 方法:
public interface Resizable {
void resize(double factor);
// default 方法提供默认实现
default void reset() {
System.out.println("Resetting to original size");
}
// static 工具方法
static String getVersion() {
return "1.0";
}
}
3
接口实现示例
public class Circle implements Drawable, Resizable {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing a circle");
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public void resize(double factor) {
radius *= factor;
}
}
第三部分:抽象类深入理解
抽象类的核心特性与模板方法模式
1
抽象类定义
public abstract class Shape {
protected String color;
protected boolean filled;
// 构造方法
public Shape(String color, boolean filled) {
this.color = color;
this.filled = filled;
}
// 抽象方法
public abstract double getArea();
public abstract double getPerimeter();
// 具体方法
public String getColor() {
return color;
}
// 模板方法模式
public final void displayInfo() {
System.out.println("Color: " + color);
System.out.println("Area: " + getArea());
System.out.println("Perimeter: " + getPerimeter());
}
}
2
继承抽象类示例
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height, String color, boolean filled) {
super(color, filled);
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
@Override
public double getPerimeter() {
return 2 * (width + height);
}
}
第四部分:实战对比案例
通过同一个需求的不同实现方式来理解差异
1
需求:动物行为建模
需要表示不同动物的共性和特性行为
方案A:接口方式
// 定义能力接口
public interface Swimmable {
void swim();
}
public interface Flyable {
void fly();
}
public interface Animal {
void eat();
void sleep();
}
// 具体实现
public class Duck implements Animal, Swimmable, Flyable {
@Override
public void eat() { System.out.println("Duck eats"); }
@Override
public void sleep() { System.out.println("Duck sleeps"); }
@Override
public void swim() { System.out.println("Duck swims"); }
@Override
public void fly() { System.out.println("Duck flies"); }
}
方案B:抽象类方式
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void eat() {
System.out.println(name + " is eating");
}
// 钩子方法
public boolean canFly() {
return false;
}
}
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " chirps");
}
@Override
public boolean canFly() {
return true;
}
}
第五部分:常见错误与最佳实践
总结开发中容易犯的错误和推荐做法
常见错误1:接口中的变量重新赋值
public interface Constants {
int MAX_COUNT = 100;
}
// 错误:试图修改接口中的变量
Constants.MAX_COUNT = 200; // 编译错误!
接口中的变量默认是 public static final,不可修改
常见错误2:抽象类实例化
abstract class Shape {
abstract double getArea();
}
// 错误:试图实例化抽象类
Shape shape = new Shape(); // 编译错误!
抽象类不能直接实例化,必须通过子类实现
常见错误3:继承冲突
interface A {
default void test() { System.out.println("A"); }
}
interface B {
default void test() { System.out.println("B"); }
}
class C implements A, B {
@Override
public void test() {
// 必须解决冲突
A.super.test(); // 或 B.super.test();
}
}
最佳实践总结
- 优先使用接口:当需要定义能力或规范时,使用接口更灵活
- 使用抽象类进行代码复用:当有公共实现需要复用时,考虑抽象类
- 组合优于继承:可以通过组合接口和抽象类来实现更灵活的设计
- 接口命名:使用形容词或以 "-able" 结尾,如 Runnable, Comparable
- 抽象类命名:使用名词,如 AbstractList, HttpServlet
第六部分:选择决策树
帮助你在实际开发中快速做出正确选择
选择接口的情况
- 需要定义一组不相关的类共有的能力
- 需要实现多继承
- 需要定义回调或事件处理
- 需要定义策略模式
- 需要定义 API 契约
选择抽象类的情况
- 需要在多个相关类间共享代码
- 需要定义模板方法模式
- 需要控制继承层次结构
- 需要定义部分实现的骨架
- 需要定义受保护的状态
实战练习
- 实现一个图形绘制系统,使用接口定义 Drawable,抽象类 Shape 提供基础实现
- 创建一个支付系统,使用接口定义 PaymentMethod,不同支付方式实现该接口
- 设计一个缓存系统,抽象类 Cache 提供基础功能,接口 Expirable 定义过期功能
第七部分:知识总结
一张思维导图总结所有核心知识点
接口特性
- 多实现支持
- Java 8+ 支持默认方法
- 只能有静态常量
- 隐式 public 抽象
抽象类特性
- 单继承限制
- 可以有构造方法
- 支持实例变量
- 支持各种访问修饰符
设计原则
- 面向接口编程
- 组合优于继承
- 高内聚低耦合
- 开闭原则
关键要点
记住这个口诀:"接口定义能力,抽象类复用代码;接口支持多实现,抽象类单继承;接口更灵活,抽象类更具体"