JAVA:抽象类和接口

发布于:2025-05-30 ⋅ 阅读:(24) ⋅ 点赞:(0)

第一章:理解抽象的本质——为什么需要抽象类?

1.1 从具体到抽象的演进

场景:开发图形绘制系统,需要处理多种形状(圆形、矩形、三角形)

初级实现(问题:重复代码):

class Circle {
    void draw() { System.out.println("绘制圆形"); }
    double area() { return 0; } // 需要具体计算
}

class Rectangle {
    void draw() { System.out.println("绘制矩形"); }
    double area() { return 0; }
}

进阶实现(引入抽象类):

abstract class Shape {
    // 抽象方法:无实现,强制子类完成
    abstract void draw();
    abstract double area();
    
    // 具体方法:公共逻辑
    void printInfo() {
        System.out.println("面积:" + area());
    }
}

class Circle extends Shape {
    double radius;
    
    @Override
    void draw() { System.out.println("⚪"); }
    
    @Override
    double area() { return Math.PI * radius * radius; }
}
1.2 抽象类的核心特性
  • 无法实例化new Shape() 会编译错误
  • 可包含混合成员:抽象方法(必须实现) + 具体方法(直接继承)
  • 构造方法存在:供子类初始化父类状态
abstract class Animal {
    String name;
    
    public Animal(String name) { this.name = name; }
    
    abstract void makeSound();
}

class Dog extends Animal {
    public Dog(String name) { super(name); }
    
    @Override
    void makeSound() { System.out.println(name + ":汪汪!"); }
}
1.3 抽象类的设计原则
  • 模板方法模式:定义算法骨架
  • abstract class Game {
        // 具体方法定义流程
        final void play() {
            initialize();
            startPlay();
            endPlay();
        }
        
        abstract void initialize();
        abstract void startPlay();
        abstract void endPlay();
    }
    
    class Chess extends Game {
        void initialize() { System.out.println("摆棋盘"); }
        void startPlay() { System.out.println("开始对弈"); }
        void endPlay() { System.out.println("收拾棋子"); }
    }
    

    第二章:接口——行为的契约

    2.1 接口的诞生背景

    需求:实现会飞的鸟和会飞的飞机,但飞行方式不同

    传统继承的局限

  • // 错误的多重继承尝试
    class Bird extends Animal, Flyable { ... } // Java不支持
    

    接口解决方案

  • interface Flyable {
        void fly(); // 默认public abstract
    }
    
    class Bird extends Animal implements Flyable {
        public void fly() { System.out.println("振翅高飞"); }
    }
    
    class Airplane implements Flyable {
        public void fly() { System.out.println("引擎推进"); }
    }
    
    2.2 接口的现代进化(Java 8+)

    默认方法:解决接口升级问题

  • interface USB {
        default void connect() {
            System.out.println("USB设备已连接");
        }
        
        void transferData();
    }
    
    class FlashDrive implements USB {
        public void transferData() {
            System.out.println("传输文件...");
        }
        // 自动继承connect()
    }
    

    静态方法:工具方法聚合

    interface MathUtils {
        static int max(int a, int b) {
            return a > b ? a : b;
        }
    }
    
    // 使用:MathUtils.max(5,3)
    
    2.3 接口的多继承威力
interface Swimmable {
    void swim();
}

interface Diving extends Swimmable {
    void deepDive();
}

class Penguin extends Bird implements Diving {
    public void swim() { System.out.println("企鹅划水"); }
    public void deepDive() { System.out.println("潜入深海"); }
}

第三章:抽象类 vs 接口——如何正确选择?

3.1 概念对比表
特性 抽象类 接口
实例化 不能 不能
方法实现 可包含具体方法 Java 8+支持默认方法
变量 任意类型 默认public static final
构造方法
继承方式 单继承 多实现
设计目的 代码复用(IS-A关系) 定义行为(CAN-DO关系)

3.2 典型应用场景

抽象类适用场景

  • 多个相关类共享代码
  • 需要定义非public成员
  • 需要定义子类的公共状态

接口适用场景

  • 定义跨继承树的行为
  • 需要多重继承
  • 定义API契约
3.3 混合使用案例

abstract class Animal {
    String name;
    public Animal(String name) { this.name = name; }
    abstract void eat();
}

interface Swimmable {
    void swim();
}

class Dolphin extends Animal implements Swimmable {
    public Dolphin() { super("海豚"); }
    
    @Override
    void eat() { System.out.println("吃鱼"); }
    
    @Override
    public void swim() { System.out.println("优雅游动"); }
}

第四章:深入接口内部——从字节码看本质

4.1 接口的编译产物

源代码

interface Logger {
    void log(String message);
    default void debug(String msg) {
        System.out.println("[DEBUG] " + msg);
    }
}

反编译结果

public interface Logger {
    public abstract void log(String message);
    public void debug(String msg) { /* 默认实现 */ }
}
4.2 默认方法的冲突解决

规则

  1. 类中的方法优先级最高
  2. 子接口覆盖父接口
  3. 必须显式解决冲突

示例

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

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

class C implements A, B {
    // 必须重写
    @Override
    public void show() {
        A.super.show(); // 明确调用A的实现
    }
}

第五章:实战演练——电商系统设计

5.1 需求分析
  • 商品分类:电子产品(保修期)、服饰(尺寸)
  • 支付方式:信用卡、支付宝
  • 物流服务:标准、加急
5.2 类图设计
<<abstract>>
Product
+ name: String
+ price: double
+ description(): void
       ▲
       |
+------+-------+
|              |
Electronics   Clothing
       ▲              ▲
       |              |
+------+------+   +---+---+
|            |   |       |
Laptop      Phone TShirt  Dress

<<interface>>
Payable
+ pay(): boolean

<<interface>>
Shippable
+ ship(): void
5.3 完整代码实现
// 抽象商品类
abstract class Product {
    String name;
    double price;
    
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
    
    abstract void description();
}

// 电子产品子类
class Electronics extends Product {
    int warrantyMonths;
    
    public Electronics(String name, double price, int warranty) {
        super(name, price);
        this.warrantyMonths = warranty;
    }
    
    @Override
    void description() {
        System.out.printf("%s 保修期:%d个月\n", name, warrantyMonths);
    }
}

// 支付接口
interface Payable {
    boolean pay(double amount);
}

// 物流接口
interface Shippable {
    void ship(String address);
}

// 具体商品实现
class Laptop extends Electronics implements Shippable {
    public Laptop() {
        super("高端笔记本", 9999.99, 24);
    }
    
    public boolean pay(double amount) {
        System.out.println("信用卡支付:" + amount);
        return true;
    }
    
    public void ship(String address) {
        System.out.println("快递发货至:" + address);
    }
}

第六章:常见陷阱与最佳实践

6.1 易犯错误
  1. 滥用继承:将"has-a"关系设计成继承

// 错误:汽车不是引擎的一种
class Car extends Engine { ... }

// 正确:使用组合
class Car {
    Engine engine;
}

2.过度抽象:过早创建不必要的抽象

// 不需要抽象的情况
abstract class StringUtils { // 应改为final类+私有构造
    static String reverse(String s) { ... }
}
6.2 设计原则
  1. 面向接口编程:声明变量时优先使用接口类型

  2. List<String> list = new ArrayList<>(); // 正确
    ArrayList<String> list = new ArrayList<>(); // 不够灵活
    

  3. 接口隔离原则:避免臃肿接口

  4. // 错误:多功能混合接口
    interface AnimalActions {
        void eat();
        void fly();
        void swim();
    }
    
    // 正确:拆分接口
    interface Flyable { void fly(); }
    interface Swimmable { void swim(); }
    

第七章:Java 17新特性——密封类与接口

7.1 密封类(Sealed Classes)

  1. 作用:限制类的继承

  2. public abstract sealed class Shape 
        permits Circle, Rectangle, Triangle {
        // 仅允许指定子类
    }
    
    final class Circle extends Shape { ... }
    

7.2 密封接口
sealed interface FileFormat 
    permits JSON, XML, CSV { ... }

第八章:综合练习与答案

8.1 练习题
  1. 设计Logger抽象类,包含:

    • 抽象方法log(String message)
    • 具体方法getTimestamp()
    • 子类FileLoggerConsoleLogger
  2. 创建Authenticator接口,包含:

    • 默认方法encrypt(String password)
    • 抽象方法login(String user, String pass)
    • 实现类DatabaseAuthenticator
8.2 参考答案
// 抽象Logger
abstract class Logger {
    String getTimestamp() {
        return Instant.now().toString();
    }
    
    abstract void log(String message);
}

class FileLogger extends Logger {
    @Override
    void log(String message) {
        String entry = getTimestamp() + " - " + message;
        // 写入文件...
    }
}

// 认证接口
interface Authenticator {
    default String encrypt(String password) {
        return Base64.getEncoder().encodeToString(password.getBytes());
    }
    
    boolean login(String user, String password);
}

class DatabaseAuthenticator implements Authenticator {
    @Override
    public boolean login(String user, String pass) {
        String encrypted = encrypt(pass);
        // 数据库验证...
        return true;
    }
}

总结:

  1. 抽象类的定义与使用场景
  2. 接口的演进与现代特性
  3. 抽象类与接口的对比选择
  4. 面向接口编程的最佳实践
  5. 复杂系统的分层设计技巧

网站公告

今日签到

点亮在社区的每一天
去签到