Skip to content

Chapter 11 · 抽象类与接口

"我只告诉你做什么,怎么做你自己想办法" — 抽象的艺术。


🎯 本章目标

  • 理解 抽象类(abstract class)的用途
  • 理解 接口(interface)及其演进(JDK 8 / 9 新特性)
  • 掌握 抽象类 vs 接口 的区别
  • 学会 多接口实现 模拟"多继承"
  • 理解 面向接口编程 思想

1. 抽象的需求

回到上一章的动物例子:

java
class Animal {
    void sound() { System.out.println("某种声音"); }   // 这个默认实现毫无意义
}

Animal.sound() 写啥都不合适:

  • 写"某种声音" → 调用方一脸懵
  • 不写 → 不能强制子类实现

解决:让 Animal 变成抽象类sound() 变成抽象方法

java
abstract class Animal {
    abstract void sound();        // 只声明,不实现
    void eat() { ... }            // 普通方法可以有实现
}

💡 抽象类不能 new,但可以被继承。子类必须实现所有抽象方法。


2. 抽象类详解

java
abstract class Animal {
    String name;
    Animal(String name) { this.name = name; }   // ✅ 可以有构造器

    abstract void sound();                       // ✅ 抽象方法(无方法体)

    void eat() {                                 // ✅ 可以有具体方法
        System.out.println(name + " 在吃饭");
    }
}

class Dog extends Animal {
    Dog(String name) { super(name); }
    @Override
    void sound() { System.out.println("汪汪"); }  // 必须实现
}

抽象类的特点

特性说明
关键字abstract class
实例化❌ 不能 new(直接),但可被继承后实例化
抽象方法abstract void m();(无方法体)
普通方法✅ 可以有
字段✅ 可以有任意字段
构造器✅ 可以有(被子类调用)
继承子类必须实现所有抽象方法(除非子类也是抽象的)

3. 接口:纯粹的"契约"

接口比抽象类更纯粹:只规定能做什么,完全不管怎么做

java
interface Flyable {
    void fly();
}

class Bird implements Flyable {
    @Override
    public void fly() { System.out.println("鸟在飞"); }
}

class Plane implements Flyable {
    @Override
    public void fly() { System.out.println("飞机在飞"); }
}

接口的演进

接口演进

Java 版本接口允许的内容
JDK 7 及以前只能有抽象方法、public static final 常量
JDK 8+ default 方法(默认实现)、static 方法
JDK 9+ private 方法(接口内部复用)

JDK 8+ 接口完整能力

java
interface Vehicle {
    int MAX_SPEED = 200;                // public static final(默认)

    void start();                       // public abstract(默认)

    default void honk() {               // 默认方法(JDK 8)
        System.out.println("嘟嘟!");
    }

    static Vehicle create(String type) { // 静态方法(JDK 8)
        return type.equals("car") ? new Car() : new Bike();
    }

    private void log(String msg) {       // 私有方法(JDK 9)
        System.out.println("[Vehicle] " + msg);
    }
}

💡 default 方法的意义:给老接口加新方法,已有实现类不需要改!这就是 Java 8 引入的关键原因(为了 Stream API 给 Collection 加方法)。


4. 多接口实现

Java 不支持多继承(一个类只能 extends 一个父类),但可以实现多个接口

java
interface Swimmable { void swim(); }
interface Flyable   { void fly(); }
interface Runnable  { void run(); }

class Duck implements Swimmable, Flyable, Runnable {
    public void swim() { System.out.println("鸭子游泳"); }
    public void fly()  { System.out.println("鸭子飞"); }
    public void run()  { System.out.println("鸭子走路"); }
}

🦆 鸭子真的能游、能飞、能跑 —— 通过多接口模拟"多继承"。


5. 抽象类 vs 接口(核心对比)

抽象类 vs 接口

维度抽象类接口
关键字abstract classinterface
字段任意类型字段只能 public static final 常量
方法任意方法(含抽象、具体)抽象 + default + static + private
构造器✅ 有❌ 无
继承单继承(extends 1 个)多实现(implements 多个)
关系"是一个"(is-a)"能做什么"(can-do)
状态可以有状态(字段)通常无状态

怎么选?

场景选择
多个类共享代码(不仅是规范)抽象类
多个类共享行为约定(仅规范)接口
需要构造器、字段抽象类
需要"伪多继承"接口
Java 8+ 给老代码加新功能接口 default

💡 现代 Java 倾向优先用接口,必要时再用抽象类辅助。


6. 面向接口编程(核心思想!)

java
// ❌ 紧耦合
class OrderService {
    AliPay payment = new AliPay();   // 写死支付宝
    void checkout() { payment.pay(100); }
}

// ✅ 面向接口
interface Payment { void pay(double amount); }

class OrderService {
    Payment payment;                 // 依赖接口,不依赖实现
    OrderService(Payment p) { this.payment = p; }
    void checkout() { payment.pay(100); }
}

new OrderService(new AliPay()).checkout();
new OrderService(new WeChatPay()).checkout();
new OrderService(new BankPay()).checkout();

好处

  • 想换支付方式?换实现类即可
  • 单元测试?传一个 mock Payment
  • 这就是 Spring 框架的"依赖注入"哲学

7. 实战练习

文件内容
AbstractClassDemo.java抽象类基础
InterfaceDemo.java接口基础与 default 方法
MultiInterface.java多接口实现
PaymentSystem.java面向接口编程实战

8. 浏览器演示

打开 demo.html

  • 抽象类 / 接口能力对照表
  • 接口 default 方法演示
  • 多接口实现可视化

9. 面试可能会问什么?

Q1: 抽象类和接口有什么区别?

维度abstract classinterface
设计意图"是一个"父子血缘"能做什么"行为约定
字段任意public static final
方法任意修饰符默认 public
构造器
继承单继承多实现

Q2: 为什么 Java 接口 JDK 8 引入 default 方法?

:保持向后兼容。Java 8 给 Collection 接口加了 stream() 方法,如果没有 default,所有已实现 Collection 的代码都会编译失败。

Q3: 接口能多继承吗?

:可以!接口 可以 extends 多个接口(注意是 extends 不是 implements):

java
interface A {}
interface B {}
interface C extends A, B {}     // ✅ 接口可以多继承

类不能多继承类,但可以实现多个接口:

java
class X extends Y implements A, B, C {}    // 限实现接口可多个

Q4: 接口的方法默认是什么修饰符?

  • 抽象方法:public abstract(编译器自动加)
  • default 方法:public
  • 字段:public static final

Q5: 什么时候用抽象类,什么时候用接口?

  • 共享 状态 + 代码 → 抽象类
  • 仅共享 行为约定 → 接口
  • 需要 "伪多继承" → 接口
  • 实在不知道?先用接口

Q6: 一个类能既继承抽象类又实现接口吗?

:可以。先 extends 后 implements:

java
abstract class Animal { ... }
interface Flyable { void fly(); }

class Bird extends Animal implements Flyable { ... }

🎁 本章小结

✅ 抽象类:可有可无具体实现,子类必须实现抽象方法
✅ 接口:行为契约,JDK 8+ 可以有 default / static 方法
✅ 类只能单继承,但可实现多个接口(伪多继承)
✅ 抽象类表"is-a",接口表"can-do"
✅ 面向接口编程是松耦合的关键

🔗 导航