必须用枚举类名调用values()(如color.values()),不可通过实例调用;它每次返回新数组,需注意性能;返回数组不可变但元素可修改,实际安全;推荐增强for遍历,避免索引循环。

直接用 values() 就行,但别在静态上下文外调用
Java 枚举类自动生成 values() 方法,返回该枚举所有实例的数组。它不是静态方法,而是由编译器注入的静态方法——所以只能通过枚举类名调用,比如 Color.values(),不能通过实例调用(color.values() 会编译报错)。
常见错误现象:Non-static method 'values()' cannot be referenced from a static context —— 实际上这个错误信息是假的,真正原因是 IDE 或旧版编译器误判;真实问题往往是写成了 this.values() 或在泛型擦除后试图反射调用却没传对类型。
- 必须用
MyEnum.values(),不能用myEnumInstance.values() - 该方法每次调用都新建数组,频繁调用要考虑缓存(尤其在循环或高频逻辑中)
- 返回数组是不可变的,但数组内容本身可被修改(Java 数组不保护元素),不过枚举实例本就是 final,所以实际安全
遍历枚举时优先用增强 for,别手写索引循环
因为 values() 返回的是普通数组,不是集合,没有 stream() 或 iterator() 原生支持(Java 12+ 才有 EnumSet.allOf(MyEnum.class) 可转集合)。增强 for 最简洁、可读性强,且 JVM 对其做了优化。
使用场景:初始化配置映射、生成下拉选项、校验输入值是否合法。
- 推荐写法:
for (Status s : Status.values()) { ... } - 避免
for (int i = 0; i —— 每次循环都调用 <code>values(),性能差 - 如果真要索引,请先缓存:
Status[] values = Status.values(); for (int i = 0; i
values() 的返回顺序就是枚举声明顺序,别依赖序号值
Java 规范明确:values() 返回的数组顺序与源码中枚举常量声明顺序严格一致。这不是巧合,是语言保证。但很多人误以为等同于 ordinal() 值,其实二者本质相同,只是表现形式不同。
容易踩的坑:把 ordinal() 当作业务含义编号(比如 OPEN(1)),结果后续加新枚举项导致所有序号偏移,下游解析全乱。
-
values()[0]永远是第一个声明的枚举常量,和MyEnum.FIRST.ordinal() == 0一致 - 不要在 JSON 序列化或数据库存储中直接用
ordinal(),改用name()或自定义字段 - 反射获取
values()时(如clazz.getMethod("values")),注意泛型擦除后返回类型是Object[],需强制转型
想动态获取任意枚举的值?用 getEnumConstants() 而非反射调 values()
如果你写的是通用工具方法(比如根据字符串反查枚举),别硬编码调 values(),而应通过 Class.getEnumConstants()。它比反射调用 values() 更轻量、更安全,且不抛 NoSuchMethodException。
性能影响:两者底层都返回同一份静态数组副本,但 getEnumConstants() 是 Class 自带方法,无反射开销。
- 正确姿势:
MyEnum.class.getEnumConstants(),返回MyEnum[],空枚举返回null - 错误姿势:
MyEnum.class.getMethod("values").invoke(null)—— 多余反射,且可能因模块限制失败(Java 9+) - 兼容性注意:非枚举类调用
getEnumConstants()返回null,务必判空
values() 看似简单,但绕不开类加载时机、数组复制开销、反射权限、以及最隐蔽的一点:它在 switch 语句编译时被 JVM 特殊处理,手动模拟时千万别试图重写或代理这个方法。Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











