Java枚举(Enum):基础语法+高级用法+实战场景+面试避坑

哈喽,各位Java开发者小伙伴!今天咱们聚焦Java中既基础又核心的知识点------枚举(Enum)。枚举自JDK 1.5引入以来,就成为了定义固定常量集合的首选方式,彻底替代了传统的"静态常量类",无论是日常开发中的状态定义、类型区分,还是面试中的高频提问,枚举都是绕不开的重点。

很多新手刚接触枚举时,只知道它能定义常量,却不懂其底层原理和高级用法;老手也可能在枚举的序列化、单例实现、接口实现等场景踩坑。本文将从"是什么、为什么用、怎么用、高级玩法、面试考点"五个维度,结合企业级实战代码,把枚举讲透,新手能快速入门,老手能查漏补缺,建议收藏备用,从此再也不怕枚举相关的问题~

一、先搞懂:Java枚举到底是什么?

一句话定义:枚举(Enum)是一种特殊的类,用于定义有限个、确定的常量集合 。它本质上是继承了java.lang.Enum类的最终类(final),编译后会生成独立的.class文件,每个枚举常量都是该枚举类的唯一实例,无法通过new关键字创建新实例。

举个通俗的例子:一年的四季(春、夏、秋、冬)、一周的七天、支付方式(微信、支付宝、银联)、HTTP状态码(200成功、404未找到、500服务器错误),这些场景的取值范围是固定且有限的,非常适合用枚举来表示。

核心本质(底层原理):

我们定义一个简单的枚举,编译后JVM会自动生成对应的class文件,其底层等价于一个继承了Enum类的final类。例如:

java 复制代码
// 我们定义的枚举
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}

// 编译后等价于(简化版)
public final class Season extends Enum<Season> {
    // 每个枚举常量都是该类的静态final实例
    public static final Season SPRING = new Season("SPRING", 0);
    public static final Season SUMMER = new Season("SUMMER", 1);
    public static final Season AUTUMN = new Season("AUTUMN", 2);
    public static final Season WINTER = new Season("WINTER", 3);
    
    // 私有构造器,禁止外部创建实例
    private Season(String name, int ordinal) {
        super(name, ordinal);
    }
    
    // 编译器自动生成values()和valueOf()方法
    public static Season[] values() { ... }
    public static Season valueOf(String name) { ... }
}

从底层代码可以看出,枚举的核心特性的是"单例性"------每个枚举常量都是唯一的实例,且由JVM保证初始化的安全性。

二、为什么要用枚举?(对比传统常量类)

在枚举出现之前,开发者通常用public static final定义静态常量类来表示固定集合,但这种方式存在明显缺陷,而枚举完美解决了这些问题,我们通过对比一目了然。

2.1 传统静态常量类的痛点

java 复制代码
// 传统静态常量类表示季节
public class SeasonConstant {
    public static final int SPRING = 1;
    public static final int SUMMER = 2;
    public static final int AUTUMN = 3;
    public static final int WINTER = 4;
}

存在3个致命问题:

  • 类型不安全:常量本质是整数,可能传入无效值(比如5),编译器无法校验,运行时容易出现逻辑错误;

  • 可读性差:调试或日志中看到的是数字(如1),而非"SPRING",需要查表对应,降低开发和调试效率;

  • 功能单一:只能表示简单的常量,无法关联更多信息(如季节的描述、月份范围等),扩展性极差。

2.2 枚举的优势(完美解决上述痛点)

  • 类型安全:枚举变量只能取枚举中定义的常量,编译器会自动校验,杜绝无效值传入;

  • 可读性强:直接使用Season.SPRING,语义清晰,日志和调试时能直接看到常量名,无需查表;

  • 可扩展性强:可以给枚举添加成员变量、方法,甚至实现接口,关联更多业务信息;

  • 天然单例+线程安全:枚举常量由JVM在类加载时初始化,且只初始化一次,天然线程安全,无需额外同步措施;

  • 序列化安全:枚举默认实现Serializable接口,JVM会保证序列化和反序列化时的唯一性,避免反射攻击。

总结:只要是表示"固定、有限的常量集合",优先使用枚举,而非静态常量类

三、基础语法:枚举的定义与常用方法(入门必练)

这部分是基础,必须掌握!我们从"简单枚举定义""带属性和构造器的枚举""枚举的默认方法"三个场景,结合代码实例讲解,直接复制就能运行。

3.1 简单枚举的定义(最基础)

语法格式:[访问修饰符] enum 枚举名 { 常量1, 常量2, ..., 常量n; }

注意:枚举常量用大写字母表示,多个常量之间用逗号分隔,末尾可加分号(也可省略);枚举名遵循Java类命名规范,首字母大写。

java 复制代码
// 定义季节枚举(简单版)
public enum Season {
    SPRING,  // 枚举常量1
    SUMMER,  // 枚举常量2
    AUTUMN,  // 枚举常量3
    WINTER;  // 枚举常量4,末尾分号可省略(此处省略不影响)
}

// 测试
public class EnumTest {
    public static void main(String[] args) {
        // 直接使用枚举常量
        Season season = Season.SPRING;
        System.out.println(season); // 输出:SPRING(默认调用toString(),返回name值)
    }
}

3.2 带属性、构造器和方法的枚举(实战常用)

枚举不仅是常量集合,还可以像普通类一样定义成员变量、构造器和方法,用于关联更多业务信息(如描述、编码等),这是实战中最常用的方式。

核心注意点:

  • 构造器必须是私有的(private),显式声明或默认都是private,确保无法在外部创建枚举实例;

  • 枚举常量的定义必须在所有成员(变量、方法)之前,否则编译报错;

  • 成员变量通常定义为final,避免被修改,保证枚举的不可变性。

java 复制代码
// 带属性、构造器和方法的季节枚举(实战版)
public enum Season {
    // 枚举常量:本质是调用构造器的实例,参数对应构造器的参数
    SPRING("春天", "3-5月"),
    SUMMER("夏天", "6-8月"),
    AUTUMN("秋天", "9-11月"),
    WINTER("冬天", "12-2月"); // 末尾分号必须加(后面有成员变量和方法)

    // 成员变量(关联业务信息)
    private final String desc;      // 季节描述
    private final String monthRange;// 月份范围

    // 私有构造器(必须是private,可省略不写,默认就是private)
    Season(String desc, String monthRange) {
        this.desc = desc;
        this.monthRange = monthRange;
    }

    // 自定义方法:获取成员变量(提供getter,不提供setter,保证不可变性)
    public String getDesc() {
        return desc;
    }

    public String getMonthRange() {
        return monthRange;
    }

    // 自定义方法:重写toString,优化输出(默认返回name,重写后更贴合业务)
    @Override
    public String toString() {
        return desc + "(" + monthRange + ")";
    }

    // 测试
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        System.out.println(spring.getDesc());      // 输出:春天
        System.out.println(spring.getMonthRange());// 输出:3-5月
        System.out.println(spring);                // 输出:春天(3-5月)
    }
}

3.3 枚举的默认方法(编译器自动生成,必记)

所有枚举类都会继承java.lang.Enum类,同时编译器会自动生成几个常用方法,无需手动定义,是日常开发中高频使用的方法。

方法名 返回类型 作用 示例
values() 枚举类型数组 返回所有枚举常量,按定义顺序排列 Season[] seasons = Season.values();
valueOf(String name) 枚举实例 根据常量名获取枚举实例(名称必须完全匹配,否则抛IllegalArgumentException) Season spring = Season.valueOf("SPRING");
ordinal() int 返回枚举常量的序号(从0开始,按定义顺序) int index = Season.SPRING.ordinal(); // 输出0
name() String 返回枚举常量的名称(与toString()默认一致,可重写toString()) String name = Season.SPRING.name(); // 输出SPRING
java 复制代码
// 枚举默认方法测试
public class EnumDefaultMethodTest {
    public static void main(String[] args) {
        // 1. values():遍历所有枚举常量
        Season[] seasons = Season.values();
        for (Season season : seasons) {
            System.out.println(season.name() + ":" + season.ordinal());
        }

        // 2. valueOf():根据名称获取枚举
        Season summer = Season.valueOf("SUMMER");
        System.out.println("获取的枚举:" + summer);

        // 3. ordinal():获取序号
        System.out.println("WINTER的序号:" + Season.WINTER.ordinal());

        // 4. name():获取常量名
        System.out.println("AUTUMN的名称:" + Season.AUTUMN.name());

        // 5. compareTo():比较序号
        System.out.println("SUMMER与SPRING的序号差值:" + Season.SUMMER.compareTo(Season.SPRING));
    }
}

运行结果:

SPRING:0 SUMMER:1 AUTUMN:2 WINTER:3 获取的枚举:夏天(6-8月) WINTER的序号:3 AUTUMN的名称:AUTUMN SUMMER与SPRING的序号差值:1

四、高级用法:枚举的进阶玩法(实战高频)

枚举的用法远不止定义常量,在企业开发中,它还可以实现接口、定义抽象方法、实现单例、配合switch使用等,这些高级用法能极大提升代码的简洁性和可维护性。

4.1 枚举实现接口(扩展行为)

枚举类不能继承其他类(因为默认继承Enum类,Java不支持多继承),但可以实现一个或多个接口,从而扩展枚举的行为,甚至让不同枚举常量实现不同的接口逻辑。

java 复制代码
// 定义一个接口(用于扩展枚举行为)
public interface Describable {
    String getDescription(); // 抽象方法:获取描述信息
}

// 枚举实现接口,每个常量重写接口方法(不同常量实现不同逻辑)
public enum Season implements Describable {
    SPRING {
        @Override
        public String getDescription() {
            return "万物复苏,春暖花开,适合踏青赏景";
        }
    },
    SUMMER {
        @Override
        public String getDescription() {
            return "烈日炎炎,蝉鸣阵阵,适合避暑纳凉";
        }
    },
    AUTUMN {
        @Override
        public String getDescription() {
            return "秋高气爽,硕果累累,适合秋游采摘";
        }
    },
    WINTER {
        @Override
        public String getDescription() {
            return "冰天雪地,银装素裹,适合滑雪赏雪";
        }
    };

    // 也可以添加通用方法(所有枚举常量共享)
    public void printInfo() {
        System.out.println(this + ":" + getDescription());
    }

    // 测试
    public static void main(String[] args) {
        for (Season season : Season.values()) {
            season.printInfo();
        }
    }
}

4.2 枚举定义抽象方法(替代switch/if-else)

可以在枚举类中定义抽象方法,然后让每个枚举常量分别实现该方法,这种方式可以替代大量的switch或if-else语句,让代码更简洁、更易维护,是策略模式的常用实现方式。

java 复制代码
// 枚举定义抽象方法,实现简单的计算器功能(策略模式简化版)
public enum Operation {
    ADD {
        @Override
        public double calculate(double a, double b) {
            return a + b;
        }
    },
    SUBTRACT {
        @Override
        public double calculate(double a, double b) {
            return a - b;
        }
    },
    MULTIPLY {
        @Override
        public double calculate(double a, double b) {
            return a * b;
        }
    },
    DIVIDE {
        @Override
        public double calculate(double a, double b) {
            if (b == 0) {
                throw new IllegalArgumentException("除数不能为0");
            }
            return a / b;
        }
    };

    // 抽象方法:每个枚举常量必须实现
    public abstract double calculate(double a, double b);

    // 测试
    public static void main(String[] args) {
        double addResult = Operation.ADD.calculate(10, 5);
        double divideResult = Operation.DIVIDE.calculate(10, 2);
        System.out.println("10+5=" + addResult);      // 输出:10+5=15.0
        System.out.println("10÷2=" + divideResult);   // 输出:10÷2=5.0
    }
}

4.3 枚举实现单例模式(最佳实践)

这是《Effective Java》中推荐的最佳单例实现方式,相比饿汉式、懒汉式,枚举实现单例更简洁、更安全,天然避免反射攻击和序列化问题,无需额外处理线程安全。

核心原理:枚举常量由JVM在类加载时初始化,且只初始化一次,天然满足单例的"唯一实例"和"线程安全"要求。

java 复制代码
// 枚举实现单例模式(简洁、安全,一行代码实现单例)
public enum Singleton {
    // 唯一的枚举常量,即单例实例(类加载时初始化,仅初始化一次)
    INSTANCE;

    // 单例的业务方法(根据实际需求定义)
    public void doSomething() {
        System.out.println("单例对象正在执行操作...");
    }

    // 测试:验证单例唯一性
    public static void main(String[] args) {
        // 获取单例实例
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;

        // 验证是否是同一个实例(== 比较即可,枚举equals()与==等价)
        System.out.println(singleton1 == singleton2); // 输出:true

        singleton1.doSomething(); // 输出:单例对象正在执行操作...
    }
}

4.4 枚举配合switch使用(简化逻辑)

枚举配合switch使用时,无需通过枚举类名引用常量,语法更简洁,且编译器会校验case的合法性,避免无效case,相比传统的int常量+switch更安全、更易读。

java 复制代码
// 枚举配合switch使用(实战常用场景:处理不同状态逻辑)
public class EnumSwitchTest {
    public static void printSeasonInfo(Season season) {
        // switch中直接使用枚举常量,无需加Season.前缀
        switch (season) {
            case SPRING:
                System.out.println("当前季节:春天,适合踏青");
                break;
            case SUMMER:
                System.out.println("当前季节:夏天,适合游泳");
                break;
            case AUTUMN:
                System.out.println("当前季节:秋天,适合秋游");
                break;
            case WINTER:
                System.out.println("当前季节:冬天,适合滑雪");
                break;
            // 无需default,编译器会校验所有枚举常量,避免遗漏(Java 14+支持switch表达式,可省略break)
        }
    }

    public static void main(String[] args) {
        printSeasonInfo(Season.AUTUMN); // 输出:当前季节:秋天,适合秋游
    }
}

4.5 枚举与Map结合(高效查找)

在实际开发中,经常需要根据枚举的某个属性(如编码)快速查找对应的枚举实例,此时可以在枚举内部定义一个静态Map,在静态代码块中初始化,实现高效查找,避免遍历枚举数组。

java 复制代码
// 枚举与Map结合,实现高效查找(实战场景:根据编码查找枚举)
import java.util.HashMap;
import java.util.Map;

public enum Currency {
    USD("美元", "$", 1),
    EUR("欧元", "€", 2),
    CNY("人民币", "¥", 3);

    // 成员变量
    private final String name;    // 货币名称
    private final String symbol;  // 货币符号
    private final int code;       // 货币编码(用于业务查找)

    // 静态Map:用于根据code快速查找枚举(O(1)查找效率)
    private static final Map<Integer, Currency&gt; CODE_MAP = new HashMap<>();

    // 静态代码块:初始化Map(类加载时执行,仅执行一次)
    static {
        for (Currency currency : values()) {
            CODE_MAP.put(currency.code, currency);
        }
    }

    // 私有构造器
    private Currency(String name, String symbol, int code) {
        this.name = name;
        this.symbol = symbol;
        this.code = code;
    }

    // 自定义方法:根据code查找枚举(对外提供查找入口)
    public static Currency getByCode(int code) {
        return CODE_MAP.get(code);
    }

    // 测试
    public static void main(String[] args) {
        Currency currency = Currency.getByCode(3);
        System.out.println(currency.name + ":" + currency.symbol); // 输出:人民币:¥
    }
}

五、实战场景:枚举在企业开发中的应用(必看)

枚举在实际开发中应用广泛,下面结合3个高频实战场景,看看企业级开发中如何正确使用枚举,提升代码质量。

场景1:定义系统状态码(最常用)

系统开发中,接口返回的状态码(如成功、失败、参数错误)是固定的,用枚举定义可以关联状态码和描述信息,避免硬编码,提升代码可维护性。

java 复制代码
// 系统状态码枚举(实战版)
public enum ResponseCode {
    SUCCESS(200, "操作成功"),
    ERROR(500, "服务器内部错误"),
    PARAM_ERROR(400, "请求参数错误"),
    NOT_FOUND(404, "资源未找到"),
    NO_PERMISSION(403, "无访问权限");

    private final int code;    // 状态码(业务编码,不依赖ordinal())
    private final String msg;  // 状态描述信息

    // 私有构造器
    private ResponseCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    // getter方法(仅提供查询,不提供修改)
    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    // 业务方法:构建接口返回结果(简化接口开发)
    public <T> Result<T> buildResult(T data) {
        return new Result<>(code, msg, data);
    }

    // 模拟接口返回结果类(实际开发中可单独定义)
    static class Result<T> {
        private int code;
        private String msg;
        private T data;

        public Result(int code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }

        // getter/setter省略
    }
}

// 接口使用示例(Controller层)
public class UserController {
    public Result<User> getUserById(int id) {
        if (id <= 0) {
            // 直接使用枚举构建错误返回,无需硬编码状态码和描述
            return ResponseCode.PARAM_ERROR.buildResult(null);
        }
        // 模拟查询用户(实际开发中调用Service层)
        User user = new User(1, "张三", 25);
        // 成功返回,语义清晰
        return ResponseCode.SUCCESS.buildResult(user);
    }
}

场景2:定义业务状态(如订单状态)

订单状态(待支付、已支付、已取消、已完成)是固定的,用枚举定义可以关联状态的编码、描述,还可以添加业务方法,判断状态的合法性(如待支付状态才能取消)。

java 复制代码
// 订单状态枚举(企业实战版)
public enum OrderStatus {
    WAIT_PAY(1, "待支付"),
    PAID(2, "已支付"),
    CANCELLED(3, "已取消"),
    COMPLETED(4, "已完成");

    private final int code;  // 订单状态编码(存储到数据库)
    private final String desc; // 状态描述

    // 静态Map:用于根据code快速查找枚举
    private static final Map<Integer, OrderStatus> CODE_MAP = new HashMap<>();

    static {
        for (OrderStatus status : values()) {
            CODE_MAP.put(status.code, status);
        }
    }

    private OrderStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    // 业务方法:判断当前状态是否可以取消(状态合法性校验)
    public boolean canCancel() {
        // 只有待支付状态可以取消
        return this == WAIT_PAY;
    }

    // 业务方法:判断当前状态是否可以支付
    public boolean canPay() {
        // 只有待支付状态可以支付
        return this == WAIT_PAY;
    }

    // 业务方法:根据code获取枚举实例(数据库查询后转换)
    public static OrderStatus getByCode(int code) {
        return CODE_MAP.getOrDefault(code, null);
    }

    // 测试
    public static void main(String[] args) {
        OrderStatus status = OrderStatus.WAIT_PAY;
        System.out.println("待支付状态是否可以取消:" + status.canCancel()); // 输出:true
        System.out.println("待支付状态是否可以支付:" + status.canPay());   // 输出:true

        OrderStatus paidStatus = OrderStatus.PAID;
        System.out.println("已支付状态是否可以取消:" + paidStatus.canCancel()); // 输出:false
    }
}

场景3:定义枚举常量,避免魔法值

开发中经常会遇到"魔法值"(硬编码的字符串、数字),导致代码可读性差、维护困难,用枚举替代魔法值,让代码更清晰、更易维护。

java 复制代码
// 反例:魔法值(硬编码,可读性差,修改困难,易出错)
public class UserService {
    public void setUserRole(String role) {
        if ("ADMIN".equals(role)) {
            // 管理员逻辑
        } else if ("USER".equals(role)) {
            // 普通用户逻辑
        }
    }
}

// 正例:枚举替代魔法值(推荐,可读性强,类型安全)
public enum UserRole {
    ADMIN("管理员"),
    USER("普通用户");

    private final String desc;

    private UserRole(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
}

// 使用枚举,避免魔法值,代码更清晰
public class UserService {
    public void setUserRole(UserRole role) {
        if (UserRole.ADMIN == role) {
            // 管理员逻辑
            System.out.println("执行管理员操作");
        } else if (UserRole.USER == role) {
            // 普通用户逻辑
            System.out.println("执行普通用户操作");
        }
    }

    // 测试
    public static void main(String[] args) {
        UserService service = new UserService();
        service.setUserRole(UserRole.ADMIN); // 输出:执行管理员操作
    }
}

六、高频坑点:6个避坑指南(新手必看)

枚举的坑点主要集中在构造器、继承、序列化、ordinal()使用等方面,结合实战中最常踩的6个坑,逐一给出解决方案,避免踩坑失分。

  • 坑点1:枚举构造器定义为public → 编译报错

  • 坑点2:枚举常量定义在成员/方法之后 → 编译报错

  • 坑点3:使用ordinal()表示业务编码 → 潜在风险

  • 坑点4:枚举继承其他类 → 编译报错

  • 坑点5:反射创建枚举实例 → 抛出异常

  • 坑点6:枚举序列化时的问题 → 破坏单例

七、面试高频题:枚举核心考点(必背)

枚举是Java面试高频考点,尤其是基础特性、底层原理、高级用法,直接看整理好的考点+标准答案,背熟就能应对面试。

考点1:Java枚举的本质是什么?(高频)

标准答案:枚举是一种特殊的类,默认继承java.lang.Enum类,且是final类,无法被继承。每个枚举常量都是该枚举类的静态final实例,由JVM在类加载时初始化,天然单例、线程安全。

考点2:枚举和静态常量类的区别?(高频)

标准答案: 1. 类型安全:枚举是强类型,只能取枚举中定义的常量,编译器校验;静态常量类是弱类型(int/string),可能传入无效值; 2. 可读性:枚举语义清晰,日志/调试时能看到常量名;静态常量类只能看到数字/字符串,需查表对应; 3. 扩展性:枚举可添加属性、方法、实现接口;静态常量类功能单一,无法扩展; 4. 安全性:枚举天然单例、线程安全、序列化安全;静态常量类需手动保证线程安全,序列化可能破坏单例。

考点3:枚举为什么不能继承其他类?可以实现接口吗?(高频)

标准答案: 不能继承其他类,因为所有枚举类默认继承java.lang.Enum类,而Java不支持多继承,因此枚举无法再继承其他类。 可以实现接口,枚举通过实现接口扩展行为,甚至可以让不同枚举常量实现不同的接口方法,实现多态。

考点4:枚举的ordinal()方法有什么坑?如何避免?

标准答案:ordinal()返回枚举常量的定义顺序(从0开始),若后续调整枚举常量的顺序(插入、删除),其返回值会发生变化,导致依赖ordinal()的业务逻辑出错。 避免方案:不要用ordinal()表示业务编码,自定义code字段存储业务编码,通过getCode()获取。

考点5:为什么说枚举实现单例是最佳方式?

标准答案: 1. 简洁:无需手动处理单例的初始化、线程安全、序列化等问题,一行代码即可实现; 2. 线程安全:JVM在类加载时初始化枚举常量,且只初始化一次,天然线程安全; 3. 防止反射攻击:JVM阻止反射创建枚举实例,避免单例被破坏; 4. 序列化安全:枚举默认实现Serializable接口,JVM保证序列化和反序列化时的唯一性,无需额外处理。

考点6:枚举可以定义抽象方法吗?如何实现?

标准答案:可以。在枚举类中定义抽象方法后,每个枚举常量必须分别实现该抽象方法,这种方式可以替代switch/if-else语句,实现策略模式,让代码更简洁、更易维护。

八、总结

Java枚举的核心价值是类型安全、简洁易用、可扩展,它不仅是定义固定常量的工具,更是提升代码可维护性、安全性的重要手段。从基础的常量定义,到高级的接口实现、单例模式、策略模式,枚举在企业开发中应用广泛。

对于新手来说,重点掌握"枚举的定义、带属性和构造器的枚举、默认方法";对于老手来说,要熟练运用枚举的高级用法,规避ordinal()、构造器、继承等坑点,结合业务场景合理使用枚举。

建议大家多动手跑一遍本文的代码,结合实际项目使用枚举,尤其是状态码、业务状态、常量定义等场景,才能真正吃透这个知识点。如果有疑问,欢迎在评论区留言讨论,一起进步~

原创不易,收藏+点赞,后续持续更新Java核心知识点!

相关推荐
鱼鳞_2 小时前
Java学习笔记_Day31(IO流)
java·笔记·学习
t***5442 小时前
能否给出更多现代C++设计模式的示例
开发语言·c++·设计模式
神仙别闹2 小时前
基于 MATLAB 实现的流载体的LSB隐藏项目
开发语言·matlab
网域小星球2 小时前
C语言从0入门(二十三)|预处理:#define、#include、条件编译详解
c语言·开发语言
石榴树下的七彩鱼2 小时前
身份证 OCR 识别 API 接入详解(Python / Java 示例)
java·开发语言·人工智能·后端·python·ocr·api
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【16】异步工具核心组件与执行流程
java·人工智能·spring
马士兵教育2 小时前
AI工作岗位的就业分层?
开发语言·人工智能·学习·面试·职场和发展
Ruihong2 小时前
你的 Vue 3 useAttrs(),VuReact 会编译成什么样的 React?
vue.js·react.js·面试