JAVA中的抽象类

文章目录


一、抽象类的定义

如果一个类不能表示一个具体的对象,此时就可以被定义为抽象类,从语法上来讲使用abstract来修饰

抽象类(abstract class)就像一个半成品模板,它定义了一组子类必须遵循的规则(方法、属性),但自己又不完整,不能直接拿来用(无法实例化),必须由子类继承并补充完整(实现抽象方法)后才能使用。

举个生活例子:"交通工具"就是一个抽象概念,它具有行驶这个通用行为,但是你没法直接创建一个交通工具实体;而"汽车""自行车"继承了交通工具,并具体实现了行驶(汽车烧油跑,自行车蹬着邹),这就是抽象类的核心思想。


二、抽象类的关键特点

  1. 不能实例化:无法直接创建抽象类的对象(比如new 交通工具()是错误的)。

  2. 包含抽象方法:抽象方法只有方法声明(定义要做什么),没有方法体(没说"怎么做"),必须由子类重写实现,前面需要加关键字abstract表示抽象方法,否则就不是抽象方法,必须存在方体。

  3. 可以包含普通方法/属性:抽象类也能有已实现的普通方法、成员变量,供子类直接使用(复用代码)。

  4. 子类必须实现所有抽象方法:除非子类也是抽象类,否则必须重写父类所有抽象方法,否则编译报错。

  5. 如果一个类当中存在抽象方法,那么这个类一定是抽象类。如果一个类是抽象类,这个类当中可以没有抽象方法

  6. 定义抽象类

java 复制代码
//用abstract关键字声明抽象类
public abstract class Vehicle {

    //普通属性:所有交通工具都有名称
    protected String name;

    //普通方法:已实现的通用逻辑,子类可直接用
    public void setName(String name) {
        this.name = name;
    }

    //抽象方法:只有声明,没有方法体(用;结尾)
    //定义了行驶这个规则,但没说具体怎么行驶
    public abstract void run();
}
  1. 子类继承并实现抽象方法
java 复制代码
//汽车类继承抽象类Vehicle
public class Car extends Vehicle{
    //必须实现父类的抽象方法run()
    @Override
    public void run() {
        System.out.println(name + "燃油,四轮行驶");
    }
}
//自行车类继承抽象类Vehicle
public class Cycle extends Vehicle {
    //必须实现父类的抽象方法run()
    @Override
    public void run() {
        System.out.println(name + "人力,两轮驱动");
    }
}

如果不实现父类的抽象方法则会发生编译错误:

使用子类(抽象类无法进行实例化)

java 复制代码
public class Test {
    public static void main(String[] args) {
        //错误:抽象类不能实例化
        //Vehicle vehicle = new Vehicle();

        //正确:实例化子类
        Vehicle car = new Car();
        car.setName("特斯拉");
        car.run();

        Vehicle bicycle = new Cycle();
        bicycle.setName("自行车");
        bicycle.run();
    }
}

三、抽象类的使用场景

  • 代码复用 + 规范约束:当多个类共同的属性 / 方法(可抽成抽象类的普通成员),但核心行为实现不同(抽成抽象方法)时,用抽象类统一规范,避免子类 "各自为政"。
  • 定义模板方法:抽象类实现核心流程(模板方法),把可变的步骤留给子类实现(比如 "制作饮品" 的模板:烧水→冲泡→装杯,其中 "冲泡" 是抽象方法,咖啡 / 茶子类分别实现)。

3.1 模板方法模式

这是抽象类最核心、最典型的应用场景,没有之一。

核心思想:抽象类定义一个算法的骨架(模板),把算法中可变的步骤延迟到子类实现,固定的通用步骤则在抽象类中实现,保证算法结构不变,同时能让子类灵活定制部分步骤。

代码示例(冲饮品场景)

java 复制代码
// 抽象类:定义冲饮品的通用模板
public abstract class Beverage {
    // 模板方法:固定算法流程(不能被子类修改,用final保护)
    public final void prepareBeverage() {
        boilWater();       // 固定步骤1:烧水
        brew();            // 可变步骤:冲泡(子类实现)
        pourInCup();       // 固定步骤2:装杯
        addCondiments();   // 可变步骤:加调料(子类实现)
    }

    // 固定方法:所有饮品都要烧水
    private void boilWater() {
        System.out.println("烧开水(100℃)");
    }

    // 固定方法:所有饮品都要装杯
    private void pourInCup() {
        System.out.println("倒入杯中");
    }

    // 抽象方法:冲泡(咖啡/茶的实现不同)
    protected abstract void brew();

    // 抽象方法:加调料(咖啡加糖奶,茶加柠檬/蜂蜜)
    protected abstract void addCondiments();
}

// 咖啡子类:实现抽象方法
public class Coffee extends Beverage {
    @Override
    protected void brew() {
        System.out.println("冲泡咖啡粉");
    }

    @Override
    protected void addCondiments() {
        System.out.println("加方糖和牛奶");
    }
}

// 茶子类:实现抽象方法
public class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("冲泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("加柠檬片");
    }
}

// 测试
public class TestTemplate {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        System.out.println("制作咖啡:");
        coffee.prepareBeverage();
        
        System.out.println("\n制作茶:");
        Beverage tea = new Tea();
        tea.prepareBeverage();
    }
}

抽象类的作用

  • 封装不变部分(烧水、装杯),避免子类重复编写;
  • 声明可变部分(冲泡、加调料)为抽象方法,强制子类实现;
  • 用final保护模板方法,防止子类篡改算法整体流程。

3.2 工厂方法模式

属于创建型模式,抽象类在这里扮演"抽象工厂"的角色,定义创建产品的接口,具体创建逻辑交给子类实现

核心思想:抽象工厂类声明一个创建产品的抽象方法,每个具体工厂子类负责创建对应的具体产品,解耦"产品创建"和"产品使用"。

》简单的用话来说就是:工厂=生产东西的地方;工厂方法=一个专门用来创建对象的方法。把创建对象的代码单独抽出来交给工厂做,你只管使用,不管怎么创建,也就是你要什么,跟工厂说,工厂给你造好,你直接用。就比如奶茶店:你去买奶茶,你不需要知道奶茶怎么煮,加多少奶加多少珍珠,你只需要和店员说我要珍珠奶茶,店员直接给你一杯做好的奶茶。这就是工厂方法模式,奶茶=对象,店员=工厂,你点单=调用工厂方法,你拿到奶茶=获取对象。

代码示例

java 复制代码
// 第一步:定义产品抽象类(所有日志记录器的通用规范)
public abstract class Logger {
    // 抽象方法:记录日志
    public abstract void log(String message);
}

// 具体产品1:文件日志记录器
public class FileLogger extends Logger {
    @Override
    public void log(String message) {
        System.out.println("写入文件:" + message);
    }
}

// 具体产品2:控制台日志记录器
public class ConsoleLogger extends Logger {
    @Override
    public void log(String message) {
        System.out.println("打印到控制台:" + message);
    }
}

// 第二步:定义抽象工厂类(创建日志记录器的工厂模板)
public abstract class LoggerFactory {
    // 抽象工厂方法:创建日志记录器(子类决定创建哪种)
    public abstract Logger createLogger();
    
    // 通用方法:获取日志器并记录(复用逻辑)
    public void recordLog(String message) {
        Logger logger = createLogger();
        logger.log(message);
    }
}

// 具体工厂1:创建文件日志器
public class FileLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        // 可添加文件日志器的初始化逻辑(如创建文件、权限检查)
        return new FileLogger();
    }
}

// 具体工厂2:创建控制台日志器
public class ConsoleLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

// 测试
public class TestFactory {
    public static void main(String[] args) {
        LoggerFactory factory1 = new FileLoggerFactory();
        factory1.recordLog("用户登录成功"); // 输出:写入文件:用户登录成功
        
        LoggerFactory factory2 = new ConsoleLoggerFactory();
        factory2.recordLog("系统启动失败"); // 输出:打印到控制台:系统启动失败
    }
}

抽象类的作用

  • Logger(产品抽象类):规范所有日志记录器的核心行为(log方法);
  • LoggerFactory(工厂抽象类):定义创建产品的接口(createLogger),同时封装通用的日志记录逻辑(recordLog),实现代码复用。
相关推荐
砍材农夫1 小时前
spring-ai 第四多模态API
java·人工智能·spring
她说..4 小时前
Java 对象相关高频面试题
java·开发语言·spring·java-ee
watson_pillow4 小时前
c++ 协程的初步理解
开发语言·c++
庞轩px4 小时前
深入理解 sleep() 与 wait():从基础到监视器队列
java·开发语言·线程··wait·sleep·监视器
故事和你915 小时前
洛谷-算法1-2-排序2
开发语言·数据结构·c++·算法·动态规划·图论
皮皮林5515 小时前
面试官:ZSet 的底层实现是什么?
java
码云数智-大飞6 小时前
C++ RAII机制:资源管理的“自动化”哲学
java·服务器·php
2601_949816586 小时前
Spring+Quartz实现定时任务的配置方法
java
白毛大侠6 小时前
理解 Go 接口:eface 与 iface 的区别及动态性解析
开发语言·网络·golang
李昊哲小课6 小时前
Python办公自动化教程 - 第7章 综合实战案例 - 企业销售管理系统
开发语言·python·数据分析·excel·数据可视化·openpyxl