Java 抽象类(Abstract Class)指南

29 阅读11分钟

🎯 Java 抽象类(Abstract Class)完全指南

📖 抽象类基本概念

什么是抽象类?

抽象类是不能实例化的类,用于定义模板规范,需要子类来实现具体的功能。

核心特征

  • 使用 abstract 关键字修饰
  • 不能创建实例(不能 new
  • 可以包含抽象方法(没有实现的方法)
  • 也可以包含具体方法(有实现的方法)
  • 必须有子类来实现抽象方法

🎯 抽象类的基本语法

1. 最简单的抽象类

// 定义抽象类
abstract class Animal {
    // 抽象方法:没有方法体,子类必须实现
    public abstract void makeSound();
    
    // 具体方法:有方法体,子类可以直接使用
    public void eat() {
        System.out.println("动物在吃东西");
    }
    
    // 可以有构造器(虽然不能new,但子类可以调用)
    public Animal() {
        System.out.println("Animal构造器被调用");
    }
}

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

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("猫喵喵叫");
    }
}

public class AbstractBasic {
    public static void main(String[] args) {
        // ❌ 错误:不能实例化抽象类
        // Animal animal = new Animal();
        
        // ✅ 正确:创建子类对象
        Dog dog = new Dog();
        dog.makeSound();  // 输出:狗汪汪叫
        dog.eat();        // 输出:动物在吃东西
        
        Cat cat = new Cat();
        cat.makeSound();  // 输出:猫喵喵叫
        cat.eat();        // 输出:动物在吃东西
        
        // ✅ 正确:向上转型(多态)
        Animal animal = new Dog();
        animal.makeSound();  // 输出:狗汪汪叫
    }
}

2. 抽象类 vs 普通类

// 普通类
class RegularClass {
    // 可以有属性
    private String name;
    
    // 可以有构造器
    public RegularClass(String name) {
        this.name = name;
    }
    
    // 可以有具体方法
    public void show() {
        System.out.println("普通类:" + name);
    }
    
    // 不能有抽象方法
    // public abstract void abstractMethod();  // 编译错误
}

// 抽象类
abstract class AbstractClass {
    // 可以有属性
    protected String name;
    
    // 可以有构造器
    public AbstractClass(String name) {
        this.name = name;
        System.out.println("AbstractClass构造器:" + name);
    }
    
    // 可以有具体方法
    public void show() {
        System.out.println("抽象类:" + name);
    }
    
    // 可以有抽象方法
    public abstract void doSomething();
    
    // 可以有静态方法
    public static void staticMethod() {
        System.out.println("抽象类的静态方法");
    }
    
    // 可以有main方法
    public static void main(String[] args) {
        System.out.println("抽象类可以有main方法");
        staticMethod();
    }
}

// 具体子类
class ConcreteClass extends AbstractClass {
    public ConcreteClass(String name) {
        super(name);  // 调用父类构造器
    }
    
    @Override
    public void doSomething() {
        System.out.println(name + "在做具体的事情");
    }
}

public class CompareDemo {
    public static void main(String[] args) {
        // 普通类
        RegularClass regular = new RegularClass("测试");
        regular.show();
        
        // 抽象类的子类
        ConcreteClass concrete = new ConcreteClass("具体类");
        concrete.show();
        concrete.doSomething();
        
        // 调用抽象类的静态方法
        AbstractClass.staticMethod();
        
        System.out.println("\n抽象类 vs 普通类:");
        System.out.println("| 特性 | 抽象类 | 普通类 |");
        System.out.println("|------|--------|--------|");
        System.out.println("| 能否实例化 | ❌ 不能 | ✅ 可以 |");
        System.out.println("| 抽象方法 | ✅ 可以有 | ❌ 不能有 |");
        System.out.println("| 继承 | 必须被继承 | 可以被继承 |");
        System.out.println("| abstract关键字 | 必须 | 不需要 |");
    }
}

🏗️ 抽象类的设计模式应用

1. 模板方法模式(Template Method)

/**
 * 模板方法模式:定义算法骨架,子类实现具体步骤
 * 抽象类定义模板方法,子类实现抽象方法
 */
abstract class DataProcessor {
    
    // 模板方法:定义算法骨架(通常用final修饰)
    public final void process() {
        System.out.println("=== 开始数据处理 ===");
        readData();
        processData();
        writeData();
        System.out.println("=== 数据处理完成 ===");
    }
    
    // 具体方法:子类可以直接使用
    protected void readData() {
        System.out.println("读取数据...");
    }
    
    // 抽象方法:子类必须实现
    protected abstract void processData();
    
    // 钩子方法:子类可以选择重写
    protected void writeData() {
        System.out.println("写入数据...");
    }
}

// 具体处理器1:CSV处理器
class CsvProcessor extends DataProcessor {
    @Override
    protected void processData() {
        System.out.println("处理CSV数据:解析逗号分隔的值");
    }
    
    @Override
    protected void writeData() {
        System.out.println("写入CSV文件");
    }
}

// 具体处理器2:JSON处理器
class JsonProcessor extends DataProcessor {
    @Override
    protected void readData() {
        System.out.println("读取JSON文件...");
    }
    
    @Override
    protected void processData() {
        System.out.println("处理JSON数据:解析对象和数组");
    }
    
    // 不重写writeData,使用父类的默认实现
}

// 具体处理器3:XML处理器
class XmlProcessor extends DataProcessor {
    @Override
    protected void processData() {
        System.out.println("处理XML数据:解析标签和属性");
    }
    
    @Override
    protected void writeData() {
        System.out.println("写入XML文件,添加XML头");
    }
}

public class TemplateMethodDemo {
    public static void main(String[] args) {
        System.out.println("=== 模板方法模式演示 ===");
        
        // 创建不同的处理器
        DataProcessor csvProcessor = new CsvProcessor();
        DataProcessor jsonProcessor = new JsonProcessor();
        DataProcessor xmlProcessor = new XmlProcessor();
        
        System.out.println("\n1. 处理CSV数据:");
        csvProcessor.process();
        
        System.out.println("\n2. 处理JSON数据:");
        jsonProcessor.process();
        
        System.out.println("\n3. 处理XML数据:");
        xmlProcessor.process();
        
        System.out.println("\n模板方法模式优点:");
        System.out.println("1. 代码复用:算法骨架在父类中定义");
        System.out.println("2. 扩展性:子类只实现具体步骤");
        System.out.println("3. 控制反转:父类控制流程,子类实现细节");
    }
}

2. 抽象工厂模式

// 抽象产品A
abstract class Button {
    public abstract void click();
}

// 抽象产品B
abstract class TextField {
    public abstract void input(String text);
}

// 抽象工厂
abstract class GUIFactory {
    public abstract Button createButton();
    public abstract TextField createTextField();
    
    // 可以添加具体方法
    public void showUI() {
        Button button = createButton();
        TextField textField = createTextField();
        
        System.out.println("显示用户界面:");
        button.click();
        textField.input("测试文本");
    }
}

// Windows风格产品
class WindowsButton extends Button {
    @Override
    public void click() {
        System.out.println("Windows风格按钮被点击");
    }
}

class WindowsTextField extends TextField {
    @Override
    public void input(String text) {
        System.out.println("Windows文本框输入: " + text);
    }
}

// Mac风格产品
class MacButton extends Button {
    @Override
    public void click() {
        System.out.println("Mac风格按钮被点击");
    }
}

class MacTextField extends TextField {
    @Override
    public void input(String text) {
        System.out.println("Mac文本框输入: " + text);
    }
}

// 具体工厂:Windows工厂
class WindowsFactory extends GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public TextField createTextField() {
        return new WindowsTextField();
    }
}

// 具体工厂:Mac工厂
class MacFactory extends GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public TextField createTextField() {
        return new MacTextField();
    }
}

public class AbstractFactoryDemo {
    public static void main(String[] args) {
        System.out.println("=== 抽象工厂模式演示 ===");
        
        // 根据配置选择工厂
        String os = "mac";  // 可以从配置文件读取
        
        GUIFactory factory;
        if ("windows".equalsIgnoreCase(os)) {
            factory = new WindowsFactory();
        } else {
            factory = new MacFactory();
        }
        
        // 使用工厂创建产品
        System.out.println("\n创建UI组件:");
        Button button = factory.createButton();
        TextField textField = factory.createTextField();
        
        button.click();
        textField.input("Hello World");
        
        // 使用模板方法
        System.out.println("\n使用模板方法显示完整UI:");
        factory.showUI();
    }
}

🔧 抽象类的实际应用

1. 支付系统设计

// 抽象支付类
abstract class Payment {
    protected String orderId;
    protected double amount;
    
    public Payment(String orderId, double amount) {
        this.orderId = orderId;
        this.amount = amount;
    }
    
    // 模板方法:支付流程
    public final boolean pay() {
        System.out.println("\n=== 开始支付流程 ===");
        System.out.println("订单号: " + orderId);
        System.out.println("金额: $" + amount);
        
        // 验证
        if (!validate()) {
            System.out.println("支付验证失败");
            return false;
        }
        
        // 执行支付
        boolean success = executePayment();
        
        // 记录日志
        logPayment(success);
        
        // 通知
        if (success) {
            notifySuccess();
        } else {
            notifyFailure();
        }
        
        return success;
    }
    
    // 抽象方法:子类必须实现
    protected abstract boolean validate();
    protected abstract boolean executePayment();
    
    // 具体方法:子类可以直接使用
    protected void logPayment(boolean success) {
        String status = success ? "成功" : "失败";
        System.out.println("记录支付日志: 订单" + orderId + " 支付" + status);
    }
    
    // 钩子方法:子类可以选择重写
    protected void notifySuccess() {
        System.out.println("发送支付成功通知");
    }
    
    protected void notifyFailure() {
        System.out.println("发送支付失败通知");
    }
    
    // 获取支付方式名称
    public abstract String getPaymentMethod();
}

// 信用卡支付
class CreditCardPayment extends Payment {
    private String cardNumber;
    private String expiryDate;
    private String cvv;
    
    public CreditCardPayment(String orderId, double amount, 
                           String cardNumber, String expiryDate, String cvv) {
        super(orderId, amount);
        this.cardNumber = cardNumber;
        this.expiryDate = expiryDate;
        this.cvv = cvv;
    }
    
    @Override
    protected boolean validate() {
        System.out.println("验证信用卡信息...");
        // 实际验证逻辑
        return cardNumber != null && cardNumber.length() == 16
            && expiryDate != null && cvv != null && cvv.length() == 3;
    }
    
    @Override
    protected boolean executePayment() {
        System.out.println("执行信用卡支付...");
        // 实际支付逻辑
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "信用卡支付";
    }
    
    @Override
    protected void notifySuccess() {
        super.notifySuccess();
        System.out.println("发送短信通知用户");
    }
}

// 支付宝支付
class AlipayPayment extends Payment {
    private String alipayAccount;
    
    public AlipayPayment(String orderId, double amount, String alipayAccount) {
        super(orderId, amount);
        this.alipayAccount = alipayAccount;
    }
    
    @Override
    protected boolean validate() {
        System.out.println("验证支付宝账户...");
        return alipayAccount != null && alipayAccount.contains("@");
    }
    
    @Override
    protected boolean executePayment() {
        System.out.println("执行支付宝支付...");
        // 调用支付宝API
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "支付宝支付";
    }
}

// 微信支付
class WechatPayment extends Payment {
    public WechatPayment(String orderId, double amount) {
        super(orderId, amount);
    }
    
    @Override
    protected boolean validate() {
        System.out.println("验证微信支付权限...");
        return true;
    }
    
    @Override
    protected boolean executePayment() {
        System.out.println("执行微信支付...");
        // 调用微信支付API
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "微信支付";
    }
    
    @Override
    protected void logPayment(boolean success) {
        // 微信支付的特殊日志格式
        System.out.println("[微信支付日志] 订单: " + orderId + 
                         ", 状态: " + (success ? "SUCCESS" : "FAIL"));
    }
}

public class PaymentSystem {
    public static void main(String[] args) {
        System.out.println("=== 支付系统演示 ===");
        
        // 创建不同的支付方式
        Payment creditCard = new CreditCardPayment("ORD001", 100.0, 
            "1234567812345678", "12/25", "123");
        Payment alipay = new AlipayPayment("ORD002", 200.0, "user@alipay.com");
        Payment wechat = new WechatPayment("ORD003", 150.0);
        
        // 执行支付
        Payment[] payments = {creditCard, alipay, wechat};
        
        for (Payment payment : payments) {
            System.out.println("\n使用" + payment.getPaymentMethod() + ":");
            boolean success = payment.pay();
            System.out.println("支付结果: " + (success ? "成功" : "失败"));
        }
    }
}

⚠️ 抽象类的注意事项

1. 构造器与初始化

abstract class Base {
    private String name;
    
    // 抽象类可以有构造器
    public Base(String name) {
        this.name = name;
        System.out.println("Base构造器: " + name);
    }
    
    public abstract void show();
    
    // 初始化块
    {
        System.out.println("Base实例初始化块");
    }
    
    // 静态初始化块
    static {
        System.out.println("Base静态初始化块");
    }
}

class Derived extends Base {
    private int value;
    
    // 子类必须调用父类构造器
    public Derived(String name, int value) {
        super(name);  // 必须放在第一行
        this.value = value;
        System.out.println("Derived构造器: value = " + value);
    }
    
    @Override
    public void show() {
        System.out.println("Derived.show()");
    }
    
    {
        System.out.println("Derived实例初始化块");
    }
}

public class ConstructorDemo {
    public static void main(String[] args) {
        System.out.println("=== 抽象类的构造器 ===");
        Derived d = new Derived("测试", 100);
        d.show();
        
        System.out.println("\n初始化顺序:");
        System.out.println("1. 父类静态初始化块");
        System.out.println("2. 子类静态初始化块");
        System.out.println("3. 父类实例初始化块");
        System.out.println("4. 父类构造器");
        System.out.println("5. 子类实例初始化块");
        System.out.println("6. 子类构造器");
    }
}

2. 抽象方法的规则

abstract class AbstractRules {
    // ✅ 正确:抽象方法
    public abstract void method1();
    
    // ✅ 正确:protected抽象方法
    protected abstract void method2();
    
    // ❌ 错误:private抽象方法
    // private abstract void method3();  // 编译错误
    
    // ❌ 错误:static抽象方法
    // static abstract void method4();   // 编译错误
    
    // ❌ 错误:final抽象方法
    // final abstract void method5();    // 编译错误
    
    // ❌ 错误:synchronized抽象方法
    // synchronized abstract void method6();  // 编译错误
    
    // ✅ 正确:抽象方法可以抛出异常
    public abstract void method7() throws Exception;
    
    // ✅ 正确:可以有具体方法
    public void concreteMethod() {
        System.out.println("具体方法");
    }
    
    // ✅ 正确:可以有静态方法
    public static void staticMethod() {
        System.out.println("静态方法");
    }
    
    // ✅ 正确:可以有final方法
    public final void finalMethod() {
        System.out.println("final方法");
    }
}

class ConcreteRules extends AbstractRules {
    // ✅ 必须实现抽象方法
    @Override
    public void method1() {
        System.out.println("实现method1");
    }
    
    @Override
    protected void method2() {
        System.out.println("实现method2");
    }
    
    @Override
    public void method7() throws Exception {
        System.out.println("实现method7");
    }
    
    // ❌ 不能重写final方法
    // @Override
    // public void finalMethod() { }
}

public class AbstractRulesDemo {
    public static void main(String[] args) {
        System.out.println("=== 抽象方法规则 ===");
        
        ConcreteRules obj = new ConcreteRules();
        obj.method1();
        obj.concreteMethod();
        obj.finalMethod();
        
        AbstractRules.staticMethod();
        
        System.out.println("\n抽象方法规则总结:");
        System.out.println("1. 抽象方法不能是 private");
        System.out.println("2. 抽象方法不能是 static");
        System.out.println("3. 抽象方法不能是 final");
        System.out.println("4. 抽象方法不能是 synchronized");
        System.out.println("5. 抽象方法可以抛出异常");
        System.out.println("6. 子类必须实现所有抽象方法");
    }
}

💡 抽象类的最佳实践

1. 何时使用抽象类?

// 场景1:有多个类共享相同的行为,但有部分行为不同
abstract class Vehicle {
    // 共同行为
    public void start() {
        System.out.println("启动交通工具");
    }
    
    // 不同行为(子类实现)
    public abstract void move();
    
    // 共同行为
    public void stop() {
        System.out.println("停止交通工具");
    }
}

// 场景2:定义模板,控制算法流程
abstract class DataProcessor {
    // 模板方法
    public final void process() {
        loadData();
        transform();
        saveResult();
    }
    
    protected abstract void loadData();
    protected abstract void transform();
    protected abstract void saveResult();
}

// 场景3:部分实现,部分未实现
abstract class Database {
    // 已实现的方法
    public Connection connect(String url) {
        // 通用连接逻辑
        return null;
    }
    
    // 未实现的方法(数据库特定)
    public abstract String getDriverClass();
    public abstract String buildConnectionString();
}

public class WhenToUse {
    public static void main(String[] args) {
        System.out.println("何时使用抽象类?");
        System.out.println("\n1. 多个类有共同行为,但有差异时");
        System.out.println("2. 需要定义算法骨架(模板方法模式)时");
        System.out.println("3. 部分实现已知,部分需要子类实现时");
        System.out.println("4. 比接口能提供更多实现细节时");
        System.out.println("\n何时使用接口?");
        System.out.println("1. 需要多重继承时");
        System.out.println("2. 只定义契约,不提供实现时");
        System.out.println("3. 需要被不相关类实现时");
    }
}

2. 设计原则

// 好的抽象类设计
abstract class GoodAbstractClass {
    // 1. 有意义的抽象方法
    public abstract void performAction();
    
    // 2. 提供有用的具体方法
    protected void commonLogic() {
        // 子类可用的通用逻辑
    }
    
    // 3. 模板方法控制流程
    public final void execute() {
        prepare();
        performAction();
        cleanup();
    }
    
    // 4. 钩子方法供子类扩展
    protected void prepare() {
        // 默认实现
    }
    
    protected void cleanup() {
        // 默认实现
    }
    
    // 5. 清晰的访问控制
    protected abstract void internalProcess();
}

// 不好的抽象类设计
abstract class BadAbstractClass {
    // ❌ 只有一个抽象方法,不如用接口
    // public abstract void singleMethod();
    
    // ❌ 太多具体实现,失去了抽象的意义
    // public void method1() { ... }
    // public void method2() { ... }
    // public void method3() { ... }
    
    // ❌ 暴露内部状态
    // public int internalState;
}

public class DesignPrinciples {
    public static void main(String[] args) {
        System.out.println("抽象类设计原则:");
        System.out.println("\n✅ 应该:");
        System.out.println("1. 提供有意义的具体实现");
        System.out.println("2. 使用模板方法定义流程");
        System.out.println("3. 使用protected访问控制");
        System.out.println("4. 提供有用的钩子方法");
        
        System.out.println("\n❌ 不应该:");
        System.out.println("1. 只有一个抽象方法(用接口)");
        System.out.println("2. 暴露内部状态");
        System.out.println("3. 有太多具体实现");
        System.out.println("4. 让子类破坏模板方法");
    }
}

📊 抽象类 vs 接口

特性抽象类接口
关键字abstract classinterface
多继承不支持支持
方法可以有具体和抽象方法Java 8前只有抽象方法
变量可以有实例变量只能是常量
构造器
访问修饰符任意默认public
设计目的代码复用,模板定义契约,能力
使用场景is-a关系,共享代码has-a关系,多重继承

🎓 总结要点

  1. 抽象类不能被实例化,必须有子类
  2. 可以包含抽象方法和具体方法
  3. 子类必须实现所有抽象方法(除非也是抽象类)
  4. 抽象类可以有构造器(用于子类初始化)
  5. 适合模板方法模式,定义算法骨架
  6. 比接口能提供更多实现细节
  7. 遵循"开闭原则",对扩展开放,对修改关闭

记住:当你发现多个类有共同行为,但部分行为需要不同实现时,考虑使用抽象类!