Skip to content

第9课:抽象类与接口

🎯 学习目标

  • 理解抽象类的概念和使用
  • 掌握接口的定义和实现
  • 理解抽象类与接口的区别
  • 掌握接口的多实现

📖 一、抽象类

1. 抽象类的概念

抽象类:不能被实例化的类,用 abstract 修饰。

java
// 抽象类
public abstract class Animal {
    String name;
    
    // 普通方法
    public void eat() {
        System.out.println(name + " is eating");
    }
    
    // 抽象方法(没有方法体)
    public abstract void makeSound();
}

// 子类必须实现所有抽象方法
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }
}

// 使用
Animal animal = new Dog();  // ✅ 可以
// Animal animal = new Animal();  // ❌ 错误:不能实例化抽象类

2. 抽象类的特点

  • ❌ 不能被实例化
  • ✅ 可以有构造方法(供子类调用)
  • ✅ 可以有抽象方法和普通方法
  • ✅ 可以有成员变量
  • ✅ 子类必须实现所有抽象方法(除非子类也是抽象类)
java
public abstract class Shape {
    String color;
    
    // 构造方法
    public Shape(String color) {
        this.color = color;
    }
    
    // 抽象方法
    public abstract double area();
    public abstract double perimeter();
    
    // 普通方法
    public void display() {
        System.out.println("Color: " + color);
    }
}

public class Circle extends Shape {
    double radius;
    
    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }
    
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }
}

📖 二、接口

1. 接口的定义

java
// 接口
public interface Flyable {
    // 抽象方法(默认 public abstract)
    void fly();
    
    // 常量(默认 public static final)
    int MAX_SPEED = 1000;
}

// 实现接口
public class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("Bird is flying");
    }
}

2. 接口的特点

  • ✅ 所有方法默认是 public abstract
  • ✅ 所有变量默认是 public static final(常量)
  • ✅ 不能有构造方法
  • ✅ 支持多实现
  • ✅ JDK 8+ 可以有默认方法和静态方法
java
public interface MyInterface {
    // 抽象方法
    void method1();
    
    // 默认方法(JDK 8+)
    default void method2() {
        System.out.println("Default method");
    }
    
    // 静态方法(JDK 8+)
    static void method3() {
        System.out.println("Static method");
    }
    
    // 私有方法(JDK 9+)
    private void method4() {
        System.out.println("Private method");
    }
}

3. 多实现

java
public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

// 一个类可以实现多个接口
public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("Duck flying");
    }
    
    @Override
    public void swim() {
        System.out.println("Duck swimming");
    }
}

📖 三、抽象类 vs 接口

特性抽象类接口
关键字abstract classinterface
继承/实现extends(单继承)implements(多实现)
构造方法✅ 可以有❌ 不能有
成员变量✅ 可以有❌ 只能有常量
方法抽象 + 普通抽象(默认) + 默认 + 静态
访问修饰符任意public(默认)

何时使用?

使用抽象类

  • IS-A 关系(猫是动物)
  • 需要共享代码
  • 需要成员变量

使用接口

  • CAN-DO 关系(鸟能飞)
  • 需要多继承行为
  • 定义规范
java
// ✅ 抽象类:IS-A 关系
abstract class Animal {
    String name;
    public abstract void eat();
}

// ✅ 接口:CAN-DO 关系
interface Flyable {
    void fly();
}

class Bird extends Animal implements Flyable {
    public void eat() { }
    public void fly() { }
}

📖 四、接口的继承

java
// 接口可以继承接口(可以多继承)
interface A {
    void methodA();
}

interface B {
    void methodB();
}

interface C extends A, B {
    void methodC();
}

// 实现 C 需要实现 A、B、C 的所有方法
class MyClass implements C {
    public void methodA() { }
    public void methodB() { }
    public void methodC() { }
}

📖 五、默认方法和静态方法

1. 默认方法(JDK 8+)

java
public interface MyInterface {
    // 默认方法
    default void log(String message) {
        System.out.println("Log: " + message);
    }
}

public class MyClass implements MyInterface {
    // 可以不重写默认方法
}

// 使用
MyClass obj = new MyClass();
obj.log("Hello");  // Log: Hello

2. 静态方法(JDK 8+)

java
public interface MyInterface {
    static void staticMethod() {
        System.out.println("Static method");
    }
}

// 使用
MyInterface.staticMethod();

3. 默认方法冲突

java
interface A {
    default void method() {
        System.out.println("A");
    }
}

interface B {
    default void method() {
        System.out.println("B");
    }
}

// 冲突:必须重写
class MyClass implements A, B {
    @Override
    public void method() {
        A.super.method();  // 调用 A 的默认方法
        // 或
        B.super.method();  // 调用 B 的默认方法
    }
}

📖 六、实战应用

1. 定义规范

java
// USB 接口规范
public interface USB {
    void connect();
    void disconnect();
    void transferData();
}

// U盘
public class UDisk implements USB {
    public void connect() {
        System.out.println("U盘已连接");
    }
    public void disconnect() {
        System.out.println("U盘已断开");
    }
    public void transferData() {
        System.out.println("传输数据");
    }
}

// 鼠标
public class Mouse implements USB {
    public void connect() {
        System.out.println("鼠标已连接");
    }
    public void disconnect() {
        System.out.println("鼠标已断开");
    }
    public void transferData() {
        System.out.println("发送鼠标数据");
    }
}

2. 策略模式

java
// 支付接口
public interface PaymentStrategy {
    void pay(double amount);
}

// 微信支付
public class WeChatPay implements PaymentStrategy {
    public void pay(double amount) {
        System.out.println("微信支付: " + amount);
    }
}

// 支付宝支付
public class AliPay implements PaymentStrategy {
    public void pay(double amount) {
        System.out.println("支付宝支付: " + amount);
    }
}

// 使用
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void checkout(double amount) {
        paymentStrategy.pay(amount);
    }
}

⚠️ 常见陷阱

陷阱1:接口设计过大

接口方法太多会迫使实现类依赖不需要的能力。接口应小而聚焦。

陷阱2:抽象类承担过多职责

抽象类如果包含大量状态和流程,很容易变成难维护的父类模板。

陷阱3:把接口当常量池

用接口只放常量是反模式,会污染实现类的 API。常量应放在专门的 final 工具类或枚举中。

陷阱4:默认方法冲突

多个接口提供同名默认方法时,实现类必须显式解决冲突。


🆚 Java vs C 对比

特性CJava
抽象能力头文件 + 函数指针约定abstract class / interface
多实现手动组合函数指针表一个类可实现多个接口
默认实现手写公共函数接口 default 方法
状态复用struct 嵌套抽象类字段和方法

对 C 程序员来说,接口可以理解为一组必须实现的函数签名;抽象类则更像带部分默认实现和状态的基类。


💡 最佳实践

  1. 接口命名:动词 + able(Runnable、Comparable、Serializable)
  2. 接口方法数量:尽量少(单一职责)
  3. 优先使用接口:比抽象类更灵活
  4. 面向接口编程:降低耦合度

📝 练习

完成 练习/Ex09_Abstract_Interface.java

  1. 抽象类实践
  2. 接口实现
  3. 多实现
  4. 默认方法
  5. 抽象类 vs 接口
  6. 综合:支付系统

🎓 下一步

  • 第10课:内部类 - 成员内部类、局部内部类、匿名内部类、静态内部类