Java 基本语法详解(七)
十八、枚举(Enum)基础
枚举是 Java 5 引入的特殊数据类型,用于定义 “固定且有限的一组常量”(如季节、星期、状态码),相比用static final常量,枚举更具类型安全性、可读性和可扩展性。
1. 枚举的核心优势
-
类型安全:枚举常量是唯一的,避免传入无效值(如用1表示 “成功”,误传5会导致逻辑错误,而枚举仅允许指定常量);
-
可读性强:直接用常量名表示含义(如Season.SPRING比1更易理解);
-
内置方法:枚举类自动继承java.lang.Enum,提供name()、ordinal()等实用方法,无需手动实现。
2. 枚举的定义与使用
(1)基本枚举定义(无属性和方法)
格式:enum 枚举名 { 常量1, 常量2, 常量3; }(常量名需全大写,多个常量用逗号分隔,末尾可加分号)。
示例:定义 “季节” 枚举
// 定义枚举类
enum Season {
SPRING, SUMMER, AUTUMN, WINTER; // 季节常量(固定4个)
}
// 使用枚举
public class EnumBasicDemo {
public static void main(String[] args) {
// 1. 直接使用枚举常量
Season currentSeason = Season.SPRING;
System.out.println("当前季节:" + currentSeason); // 输出:当前季节:SPRING
// 2. 枚举的内置方法
System.out.println("枚举常量名:" + currentSeason.name()); // 输出:枚举常量名:SPRING
System.out.println("枚举常量索引(从0开始):" + currentSeason.ordinal()); // 输出:枚举常量索引(从0开始):0
// 3. 遍历所有枚举常量(values()方法:返回枚举数组)
System.out.print("所有季节:");
for (Season season : Season.values()) {
System.out.print(season + " "); // 输出:所有季节:SPRING SUMMER AUTUMN WINTER
}
// 4. 枚举比较(直接用==,无需equals())
if (currentSeason == Season.SPRING) {
System.out.println("\n当前是春季,适合踏青!"); // 输出:当前是春季,适合踏青!
}
}
}
(2)带属性和方法的枚举(增强版)
枚举本质是 “特殊的类”,可包含成员变量、构造方法和成员方法,实现更复杂的逻辑(如给每个常量绑定额外信息)。
示例:定义 “订单状态” 枚举(含状态码和描述)
// 带属性和方法的枚举
enum OrderStatus {
// 枚举常量:需匹配构造方法参数(顺序:状态码,描述)
PENDING(100, "待支付"),
PAID(200, "已支付"),
SHIPPED(300, "已发货"),
DELIVERED(400, "已送达"),
CANCELLED(500, "已取消");
// 成员变量(枚举的属性)
private final int code; // 状态码(final:初始化后不可修改)
private final String desc; // 状态描述
// 构造方法(枚举构造方法必须是private,且只能在枚举内部调用)
private OrderStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
// 成员方法(获取属性值)
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
// 自定义方法:根据状态码获取枚举常量
public static OrderStatus getByCode(int code) {
for (OrderStatus status : OrderStatus.values()) {
if (status.getCode() == code) {
return status;
}
}
throw new IllegalArgumentException("无效的订单状态码:" + code); // 无匹配时抛异常
}
}
// 使用带属性的枚举
public class EnumAdvancedDemo {
public static void main(String[] args) {
// 1. 获取枚举常量的属性
OrderStatus status = OrderStatus.PAID;
System.out.println("订单状态:" + status); // 输出:订单状态:PAID
System.out.println("状态码:" + status.getCode()); // 输出:状态码:200
System.out.println("状态描述:" + status.getDesc()); // 输出:状态描述:已支付
// 2. 调用自定义方法(根据状态码获取枚举)
OrderStatus statusByCode = OrderStatus.getByCode(300);
System.out.println("状态码300对应的状态:" + statusByCode.getDesc()); // 输出:状态码300对应的状态:已发货
// 3. 模拟订单状态流转
OrderStatus orderStatus = OrderStatus.PENDING;
System.out.println("\n初始订单状态:" + orderStatus.getDesc());
orderStatus = OrderStatus.PAID;
System.out.println("用户支付后状态:" + orderStatus.getDesc());
orderStatus = OrderStatus.SHIPPED;
System.out.println("商家发货后状态:" + orderStatus.getDesc());
}
}
输出结果:
订单状态:PAID
状态码:200
状态描述:已支付
状态码300对应的状态:已发货
初始订单状态:待支付
用户支付后状态:已支付
商家发货后状态:已发货
十九、注解(Annotation)基础
注解(也称 “标注”)是 Java 5 引入的特殊语法,用于 “为代码添加元数据”(如说明方法功能、标记类的用途),不直接影响代码逻辑,但可被编译器、框架(如 Spring)或工具解析,实现自动化处理(如自动生成代码、参数校验)。
1. 注解的核心作用
-
编译器提示:如@Override标记方法重写,编译器会校验是否符合重写规则;
-
框架配置:如 Spring 的@Component标记类为 “组件”,框架自动扫描并创建对象;
-
代码分析:如@Deprecated标记 “过时” 方法,IDE 会提示开发者避免使用;
-
自定义逻辑:通过自定义注解 + 解析器,实现个性化需求(如参数校验、日志记录)。
2. Java 内置注解(常用)
Java 提供了 3 个核心内置注解,直接用于代码标记:
| 注解名 | 作用描述 |
|---|---|
| @Override | 标记方法是 “重写父类的方法”,编译器会校验:方法名、参数列表、返回值是否与父类一致 |
| @Deprecated | 标记 “过时” 的类 / 方法 / 字段,提示开发者该元素已不推荐使用,存在更好的替代方案 |
| @SuppressWarnings | 抑制编译器产生的 “警告信息”(如未使用变量警告、未检查类型转换警告),需指定警告类型 |
示例:内置注解的使用
public class BuiltInAnnotationDemo {
public static void main(String[] args) {
// 调用过时方法(IDE会提示警告)
OldUtils.oldMethod();
// 抑制“未使用变量”警告
@SuppressWarnings("unused")
String unusedVar = "这是未使用的变量";
// 创建子类对象并调用重写方法
Animal dog = new Dog();
dog.makeSound();
}
}
// 父类
class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
// 子类:@Override标记方法重写
class Dog extends Animal {
// @Override:若方法名写错(如makeSound1),编译器会报错
@Override
public void makeSound() {
System.out.println("小狗汪汪叫");
}
}
// 过时工具类:@Deprecated标记
class OldUtils {
// 标记方法过时,并说明替代方案
@Deprecated(since = "1.0", forRemoval = true, message = "请使用NewUtils.newMethod()替代")
public static void oldMethod() {
System.out.println("这是过时的方法,不推荐使用!");
}
}
// 新工具类(替代OldUtils)
class NewUtils {
public static void newMethod() {
System.out.println("这是新方法,推荐使用!");
}
}
说明:
-
@Deprecated的属性:since表示 “从哪个版本开始过时”,forRemoval表示 “未来是否会删除”,message表示 “提示信息”;
-
@SuppressWarnings的警告类型:unused抑制 “未使用变量” 警告,rawtypes抑制 “未指定泛型” 警告,all抑制所有警告(不推荐)。
3. 自定义注解(基础)
除了内置注解,还可自定义注解,实现特定业务逻辑(需结合 “元注解” 和 “解析器”)。
(1)自定义注解的格式
自定义注解需用@interface声明,且必须搭配 “元注解”(描述注解本身的注解),常用元注解:
| 元注解名 | 作用描述 |
|---|---|
| @Target | 指定注解可作用的 “目标元素”(如类、方法、字段),取值:TYPE(类)、METHOD(方法)、FIELD(字段)等 |
| @Retention | 指定注解的 “保留周期”,取值:SOURCE(仅源码)、CLASS(源码 + 字节码)、RUNTIME(源码 + 字节码 + 运行时,可通过反射解析) |
| @Documented | 标记注解是否会被javadoc工具生成到 API 文档中 |
| @Inherited | 标记注解是否会被 “子类继承”(仅作用于类级别的注解) |
示例:自定义 “日志注解”(标记需要打印日志的方法)
import java.lang.annotation.*;
// 1. 自定义注解(@Log:标记方法需打印日志)
@Target(ElementType.METHOD) // 注解仅作用于“方法”
@Retention(RetentionPolicy.RUNTIME) // 保留到运行时,支持反射解析
@Documented // 生成API文档时包含该注解
public @interface Log {
// 注解的属性(可选,格式:类型 名称() [default 默认值];)
String value() default "执行方法"; // 日志描述,默认值“执行方法”
}
// 2. 业务类:使用自定义@Log注解
class UserService {
// 标记方法需打印日志,指定日志描述
@Log("用户登录")
public void login(String username) {
System.out.println("用户[" + username + "]登录成功");
}
// 标记方法需打印日志,使用默认日志描述
@Log
public void logout(String username) {
System.out.println("用户[" + username + "]退出登录");
}
}
// 3. 注解解析器:通过反射解析@Log注解,实现日志打印
import java.lang.reflect.Method;
public class AnnotationParser {
public static void main(String[] args) throws Exception {
// 创建业务类对象
UserService userService = new UserService();
// 反射获取UserService的Class对象
Class<?> serviceClass = UserService.class;
// 调用登录方法(带日志)
Method loginMethod = serviceClass.getMethod("login", String.class);
invokeWithLog(loginMethod, userService, "zhangsan");
// 调用退出方法(带日志)
Method logoutMethod = serviceClass.getMethod("logout", String.class);
invokeWithLog(logoutMethod, userService, "zhangsan");
}
// 带日志的方法调用:解析@Log注解并打印日志
private static void invokeWithLog(Method method, Object obj, Object... args) throws Exception {
// 判断方法是否有@Log注解
if (method.isAnnotationPresent(Log.class)) {
// 获取@Log注解对象
Log logAnnotation = method.getAnnotation(Log.class);
// 获取注解的属性值(日志描述)
String logDesc = logAnnotation.value();
// 打印日志(模拟日志框架的功能)
System.out.println("[日志] " + logDesc + ":开始执行");
// 调用目标方法(反射执行)
method.invoke(obj, args);
// 打印方法执行完成日志
System.out.println("[日志] " + logDesc + ":执行完成\n");
} else {
// 无@Log注解,直接调用方法
method.invoke(obj, args);
}
}
}
输出结果:
[日志] 用户登录:开始执行
用户[zhangsan]登录成功
[日志] 用户登录:执行完成
[日志] 执行方法:开始执行
用户[zhangsan]退出登录
[日志] 执行方法:执行完成
说明:自定义注解的核心是 “注解定义 + 解析器”,解析器通过反射(Class、Method类)获取注解信息,进而实现业务逻辑(如日志打印、参数校验),这也是 Spring、MyBatis 等框架的核心原理之一。
二十、Java 基础语法扩展建议
掌握上述基础语法后,可从以下方向进一步扩展学习,逐步向 “Java 开发工程师” 进阶:
-
集合框架深入:学习LinkedList、HashMap、HashSet等集合的底层实现(如数组 + 链表、红黑树),理解不同集合的适用场景;
-
IO 流进阶:学习缓冲流(BufferedInputStream)、转换流(InputStreamReader)、对象流(ObjectOutputStream),掌握文件复制、对象序列化等实用功能;
-
多线程编程:学习Thread类、Runnable接口、线程池、锁机制(synchronized、Lock),理解并发编程的核心思想;
-
反射与注解:深入学习反射 API(Class、Constructor、Field),结合自定义注解实现框架级功能(如 ORM 映射、接口文档自动生成);
-
数据库操作:学习 JDBC 基础(连接数据库、CRUD 操作),进而学习 MyBatis、Spring Data JPA 等持久层框架;
-
Web 开发入门:学习 Servlet、JSP 基础,了解 HTTP 协议,进而学习 Spring Boot 框架,快速开发 Web 应用。
Java 基础是后续进阶的基石,建议通过 “理论学习 + 代码实践” 结合的方式,多写案例(如学生管理系统、图书管理系统),逐步积累开发经验,提升解决实际问题的能力。


被折叠的 条评论
为什么被折叠?



