当前位置: 首页 > news >正文

JavaSE基础——第九章 枚举类注解

本专题主要为观看韩顺平老师《零基础30天学会Java》课程笔记,同时也会阅读其他书籍、学习其他视频课程进行学习笔记总结。如有雷同,不是巧合!

一、枚举类(Enum)

1.枚举类出现的原因

(1)替代传统常量的缺陷

在枚举出现之前,Java 使用 public static final 定义常量(如 intString 类型),但这种方式存在明显问题:

  • 类型不安全常量本质上是普通变量,编译器无法检查值的合法性

    public static final int SPRING = 1;
    public static final int SUMMER = 2;void setSeason(int season) { ... }// 问题:可以传入任意 int 值(如 99),编译器不会报错
    setSeason(99);
    

    但是可以将构造器私有化,提供get方法,但不提供set方法。类似于饿汉式单例设计模式。例如public static final Season SPRINT = new Season(”春天”, “温暖”);

  • 可读性差:常量是分散的,缺乏逻辑关联。

  • 功能单一:常量只是值,无法附加行为或属性。

枚举的解决方案

将常量定义为枚举类型,编译器会强制类型检查,非法值无法通过编译:

enum Season { SPRING, SUMMER; }
void setSeason(Season season) { ... }setSeason(Season.SPRING); // 正确
setSeason(99);            // 编译错误!

(2)需要更强大的常量表达方式

传统常量无法表达复杂场景,例如:

  • 常量需要关联额外属性(如枚举值对应描述、编号等)。
  • 常量需要定义特定行为(如不同枚举值执行不同逻辑)。

枚举的解决方案

枚举可以像类一样定义字段、方法和构造函数:

enum Planet {EARTH(5.97e24, 6371),MARS(6.39e23, 3389);private final double mass; // 质量private final double radius; // 半径Planet(double mass, double radius) {this.mass = mass;this.radius = radius;}public double surfaceGravity() {return 6.67e-11 * mass / (radius * radius);}
}

(3)替代枚举模式的实现

在枚举出现前,开发者通过以下方式模拟枚举:

  • 常量类(类型不安全,如 public static final)。

  • 类型安全枚举模式(Joshua Bloch 在《Effective Java》中提出),需要大量模板代码:

    public class Season {private final String name;private Season(String name) { this.name = name; }public static final Season SPRING = new Season("Spring");// 其他季节...
    }
    

(4)支持面向对象特性

枚举本质上是类(继承自 java.lang.Enum),因此可以:

  • 实现接口。

  • 覆盖方法。

  • 定义抽象方法并由不同枚举值实现多态:

    enum Operation {ADD { double apply(double x, double y) { return x + y; } },SUBTRACT { double apply(double x, double y) { return x - y; } };abstract double apply(double x, double y);
    }
    

(5)线程安全与单例优化

枚举天然适合实现单例模式:

  • 实例由 JVM 在加载枚举类时创建,保证线程安全。
  • 防止反射攻击(传统单例可能被反射破坏)。
enum Singleton {INSTANCE;public void doSomething() { ... }
}

2.枚举介绍

枚举(Enum)是 Java 5 引入的一种特殊数据类型,用于定义一组固定的常量。枚举类比传统的常量定义(如 public static final)更安全、更强大。

基本语法

访问修饰符 enum 枚举类名 {常量名1(实参列表), 常量名1(实参列表), ...;   // 一定要写在最前面成员变量;构造函数;成员方法;
}使用 枚举类名.常量名 访问
public enum Season {SPRING, SUMMER, AUTUMN, WINTER;
}
  • 枚举常量本身隐式是 public static final,无需也不能显式添加修饰符。
  • 构造器必须是 private(可省略,默认就是 private),因为枚举常量必须在枚举类内部实例化,外部无法通过 new 创建。
    • 枚举的本质是固定数量的实例(如 Color.REDColor.GREEN),不允许运行时动态创建。
    • 安全性:防止外部通过反射或其他方式破坏枚举的单例特性。
    • 如果尝试声明非 private 构造器,编译器会报错。
  • 安全性:防止外部通过反射或其他方式破坏枚举的单例特性
  • 使用无参构造器创建枚举对象时,实参列表和小括号都可以省略
  • 有多个枚举对象时,使用,间隔,使用;结尾
  • 枚举对象必须放在枚举类的行首

枚举的特点

  1. 类型安全:编译器会检查类型,避免传入无效值
  2. 自带方法:枚举类自动继承 java.lang.Enum,提供了一些有用方法【不能再继承其他类】
  3. 可添加自定义属性和方法:枚举可以像普通类一样定义字段和方法
  4. 可实现接口:枚举可以实现一个或多个接口
  5. 可用于switch语句:枚举类型可以直接用于switch-case

枚举的常用方法

所有枚举类型都隐式继承 Enum 类,因此有以下方法:

  • name():返回枚举常量的名称(字符串)
  • ordinal():返回枚举常量的序数(声明时的位置,从0开始)
  • values():返回包含所有枚举常量的数组(编译器生成)
  • valueOf(String name):根据名称返回对应的枚举常量

高级用法

(1)带参数的枚举

public enum Planet {MERCURY(3.303e+23, 2.4397e6),VENUS(4.869e+24, 6.0518e6),EARTH(5.976e+24, 6.37814e6);private final double mass;   // 质量(kg)private final double radius; // 半径(m)Planet(double mass, double radius) {this.mass = mass;this.radius = radius;}public double surfaceGravity() {return 6.67300E-11 * mass / (radius * radius);}
}

(2)枚举实现接口

public interface Command {void execute();
}public enum LogLevel implements Command {ERROR {public void execute() {System.err.println("Error logging");}},WARN {public void execute() {System.out.println("Warning logging");}};
}

(3)枚举单例模式

public enum Singleton {INSTANCE;public void doSomething() {System.out.println("Singleton operation");}
}

使用示例

public class EnumExample {public static void main(String[] args) {// 遍历枚举for (Season s : Season.values()) {System.out.println(s);}// switch使用Season current = Season.SUMMER;switch (current) {case SPRING:System.out.println("春暖花开");break;case SUMMER:System.out.println("夏日炎炎");break;// 其他case...}// 调用枚举方法System.out.println("Earth gravity = " + Planet.EARTH.surfaceGravity());}
}

枚举与设计模式

枚举是实现以下设计模式的优秀选择:

  • 单例模式(Singleton)
  • 策略模式(Strategy)
  • 状态模式(State)
  • 命令模式(Command)

Enum类的常用方法

1. 核心方法

name()

  • 作用:返回枚举常量的名称(声明时的名字)
  • 特点:是 final 方法,不能重写
  • 示例
enum Color { RED, GREEN, BLUE }public class Main {public static void main(String[] args) {System.out.println(Color.RED.name()); // 输出 "RED"}
}

ordinal()

  • 作用:返回枚举常量的序数(声明时的位置,从0开始)
  • 特点:通常不建议依赖此值,因为改变枚举顺序会影响结果
  • 示例
System.out.println(Color.RED.ordinal()); // 输出 0
System.out.println(Color.GREEN.ordinal()); // 输出 1

values()

  • 作用:返回包含所有枚举常量的数组(按声明顺序)
  • 特点:编译器自动生成的方法,不在 Enum 类中
  • 示例
for (Color c : Color.values()) {System.out.println(c);
}
// 输出:
// RED
// GREEN
// BLUE

valueOf(String name)

  • 作用:将字符串转换成枚举对象,根据名称返回对应的枚举常量,要求字符串必须是已有的常量名。
  • 特点:区分大小写,如果名称不存在会抛出 IllegalArgumentException
  • 示例
Color red = Color.valueOf("RED"); // 返回 Color.RED

2. 实用方法

toString()

  • 作用:默认返回与 name() 相同的结果【return name;】,但可以重写
  • 示例
enum Color {RED("红色"), GREEN("绿色"), BLUE("蓝色");private String chineseName;Color(String name) {this.chineseName = name;}@Overridepublic String toString() {return this.chineseName;}
}System.out.println(Color.RED); // 输出 "红色"

compareTo(E o)

  • 作用:比较两个枚举常量的顺序(基于 ordinal 值)
  • 返回值:负数(小于)、0(等于)、正数(大于)
  • 示例
Color.RED.compareTo(Color.BLUE); // 返回负数(RED在BLUE前面)

equals(Object other)

  • 作用:比较两个枚举常量是否相同
  • 特点:可以直接使用 == 比较,因为枚举常量是单例
  • 示例
Color.RED.equals(Color.RED); // true
Color.RED == Color.RED; // true

3. 高级用法

getDeclaringClass()

  • 作用:返回枚举常量的枚举类型 Class 对象
  • 示例
Class<Color> colorClass = Color.RED.getDeclaringClass();

4.实现接口方法

枚举可以实现接口,并为每个常量提供不同的实现:

interface Operation {int apply(int a, int b);
}enum BasicOperation implements Operation {PLUS {public int apply(int a, int b) { return a + b; }},MINUS {public int apply(int a, int b) { return a - b; }};
}System.out.println(BasicOperation.PLUS.apply(2, 3)); // 输出 5

5. 使用建议

  1. 优先使用 name() 而非 toString():除非需要自定义输出
  2. 避免依赖 ordinal():因为枚举顺序可能会变化
  3. 使用 == 比较枚举:比 equals() 更高效
  4. 考虑实现接口:使枚举更具灵活性
  5. 利用 values() 进行遍历:比反射更安全高效

5. 完整示例

enum Planet {MERCURY(3.303e+23, 2.4397e6),VENUS(4.869e+24, 6.0518e6),EARTH(5.976e+24, 6.37814e6);private final double mass;   // 质量(kg)private final double radius; // 半径(m)Planet(double mass, double radius) {this.mass = mass;this.radius = radius;}public double surfaceGravity() {return 6.67300E-11 * mass / (radius * radius);}public double surfaceWeight(double otherMass) {return otherMass * surfaceGravity();}
}public class Main {public static void main(String[] args) {// 遍历所有行星for (Planet p : Planet.values()) {System.out.printf("%s: %.2f m/s²%n", p, p.surfaceGravity());}// 根据名称获取枚举Planet earth = Planet.valueOf("EARTH");System.out.println("Earth's gravity: " + earth.surfaceGravity());}
}

二、注解(Annotation

注解(Annotation)是Java 5引入的一种**元数据(Metadata)**形式,用于修饰包、类、方法、属性、构造器、局部变量等,它提供了一种向代码添加结构化信息的方式,这些信息可以被编译器、开发工具或运行时环境读取和使用。

  • 和注释一样。不影响程序逻辑;但注解可以被编译或运行,相当于嵌入在代码中的补充信息

(一)注解的基本概念

注解是一种特殊的接口,以@符号为前缀,可以附加在包、类、方法、字段、参数等代码元素上,用于提供额外的信息。

基本语法

@AnnotationName
public class MyClass {@AnnotationNamepublic void myMethod() {// ...}
}

(二)Java内置的常用注解

实际上还是一个类,可以定义属性和方法。

1. 编译时注解

  • @Override - 表示方法覆盖了父类方法,只能用于注解方法

  • @Deprecated - 表示方法、类、字段、包、参数等已过时,不再推荐使用,但仍可以用

  • @SuppressWarnings({""}) -写入希望抑制编译器的警告类型

2. 元注解(用于定义注解的注解)

  • @Target - 指定注解可以应用的目标,比如@Target(ElementType.METHOD)表示只能修饰方法

  • @Retention - 指定注解的保留策略,即注解的作用范围【3种:SOURCE(源码), CLASS(类),RUNTIME(运行时)】

  • @Documented - 表示注解应包含在Javadoc中

  • @Inherited - 表示注解可以被子类继承

  • @Repeatable(Java 8+) - 表示注解可以重复应用于同一元素

(三)自定义注解

可以创建自己的注解类型:

1. 定义注解

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {String value() default "default value";int count() default 1;
}

@interface表示一个注解类

2. 使用注解

public class AnnotationTest {@MyAnnotation(value = "test", count = 5)public void testMethod() {// ...}
}

(四)注解的保留策略

通过@Retention指定注解的保留时间:

  1. RetentionPolicy.SOURCE - 仅保留在源码中,编译时丢弃
  2. RetentionPolicy.CLASS - 保留在class文件中,但运行时不可见(默认)
  3. RetentionPolicy.RUNTIME - 保留到运行时,可以通过反射读取

(五)注解的目标类型

通过@Target指定注解可以应用的位置:

@Target({ElementType.TYPE,           // 类、接口、枚举ElementType.FIELD,          // 字段ElementType.METHOD,         // 方法ElementType.PARAMETER,      // 参数ElementType.CONSTRUCTOR,    // 构造器ElementType.LOCAL_VARIABLE, // 局部变量ElementType.ANNOTATION_TYPE,// 注解ElementType.PACKAGE,        // 包ElementType.TYPE_PARAMETER, // 类型参数(Java 8+)ElementType.TYPE_USE        // 类型使用(Java 8+)
})

(六)注解的处理

1. 编译时处理

通过注解处理器(Annotation Processor)在编译时处理注解。

2. 运行时处理

通过反射API在运行时处理注解:

Method method = AnnotationTest.class.getMethod("testMethod");
if (method.isAnnotationPresent(MyAnnotation.class)) {MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);System.out.println("Value: " + annotation.value());System.out.println("Count: " + annotation.count());
}

(七)Java 8对注解的增强

1. 可重复注解

@Repeatable(Authorities.class)
public @interface Authority {String role();
}public @interface Authorities {Authority[] value();
}@Authority(role="admin")
@Authority(role="manager")
public class User {// ...
}

2. 类型注解

可以在任何使用类型的地方添加注解:

List<@NonNull String> list = new ArrayList<>();

(八)注解的常见应用场景

  1. 代码生成:如Lombok库
  2. 配置替代:如Spring的@Component@Autowired
  3. 测试框架:如JUnit的@Test
  4. 文档生成:如Swagger的API文档
  5. 验证框架:如Bean Validation的@NotNull

http://www.dtcms.com/a/393507.html

相关文章:

  • 云计算在金融领域中的应用
  • 【入门算法】前缀和:先预存再求和,以空间换时间
  • mac编译vst3sdk
  • Java 网络原理(二)--- TCP的机制 + IP协议 +以太网协议 + DNS
  • Python文件名编码处理深度解析:绕过编码问题的专业指南
  • 如何利用简单的浏览器插件Web Scraper爬取知乎评论数据
  • 鹿鼎记豪侠传:Rust 重塑 iOS 江湖(下)
  • 03.博客版-镜像
  • 云原生docker离线二进制安装
  • RabbitMQ 的配置文件位置及常见配置项
  • Visual Prompt Builder-AI 提示词可视化工具
  • 一文掌握Flask:从基础使用到高级应用
  • 23种设计模式之【责任链模式】-核心原理与 Java 实践
  • 执行 conda update -n base -c defaults conda 后仍提示需要升级
  • 学习日报 20250921|NIO
  • 【Linux操作系统】Linux基础指令和权限
  • 谷歌nano banana官方Prompt模板
  • 基于Python大数据的新闻推荐分析
  • ​​[硬件电路-315]:AD7606BSTZ如何测量失调电压?
  • 微服务-分布式追踪 / 监控工具大全
  • The Library: 2靶场渗透
  • 金融知识“厦”乡趣 平安产险厦门分公司启动2025年“金融教育宣传周”活动
  • C++学习笔记——模板初阶
  • Windows 下 WSL2 生态:Ubuntu/Docker Desktop 关系、VLLM 部署差异与性能解析
  • 智能体技术革命:从华为金融智能体FAB看AI智能体的未来发展与行业影响
  • CIKM 2025 | FinCast:用于金融时间序列预测的基础模型
  • 论文解读——矩形隧道中MIMO信道特性的模态理论解释
  • Mac brew VSCode Python3
  • 【C++】list 的使用及迭代器底层详解
  • NumPy 系列(三):numpy 数组的索引