扒一扒: Java 中的枚举

在 Java 中, 枚举, 也称为枚举类型, 其是一种特殊的数据类型, 它使得变量能够称为一组预定义的常量。 其目的是强制编译时类型安全。

因此, 在 Java 中, enum 是保留的关键字。

保留的关键字

1. 枚举的定义

在 Java 是在 JDK 1.4 时决定引入的, 其在 JDK 1.5 发布时正式发布的。

举一个简单的例子:以日常生活中的方向来定义, 因为其名称, 方位等都是确定, 一提到大家就都知道。

1.1 传统的非枚举方法

如果不使用枚举, 我们可能会这样子定义

public class Direction { public static final int EAST = 0; public static final int WEST = 1; public static final int SOUTH = 2; public static final int NORTH = 3; }

以上的定义也是可以达到定义的, 我们在使用时

@Test public void testDirection() { System.out.println(getDirectionName(Direction.EAST)); System.out.println(getDirectionName(5));// 也可以这样调用 } public String getDirectionName(int type) { switch (type) { case Direction.EAST: return "EAST"; case Direction.WEST: return "WEST"; case Direction.SOUTH: return "SOUTH"; case Direction.NORTH: return "NORTH"; default: return "UNKNOW"; } }

运行起来也没问题。 但是, 我们就如同上面第二种调用方式一样, 其实我们的方向就在 4 种范围之内,但在调用的时候传入不是方向的一个 int 类型的数据, 编译器是不会检查出来的。

1.2 枚举方法

我们使用枚举来实现上面的功能

定义

public enum DirectionEnum { EAST, WEST, NORTH, SOUTH }

测试

@Test public void testDirectionEnum() { System.out.println(getDirectionName(DirectionEnum.EAST)); // System.out.println(getDirectionName(5));// 编译错误 } public String getDirectionName(DirectionEnum direction) { switch (direction) { case EAST: return "EAST"; case WEST: return "WEST"; case SOUTH: return "SOUTH"; case NORTH: return "NORTH"; default: return "UNKNOW"; } }

以上只是一个举的例子, 其实, 枚举中可以很方便的获取自己的名称。

通过使用枚举, 我们可以很方便的限制了传入的参数, 如果传入的参数不是我们指定的类型, 则就发生错误。

1.3 定义总结

以刚刚的代码为例

public enum DirectionEnum { EAST, WEST, NORTH, SOUTH }

枚举类型的定义跟类一样, 只是需要将 class 替换为 enum

枚举名称与类的名称遵循一样的惯例来定义

枚举值由于是常量, 一般推荐全部是大写字母

多个枚举值之间使用逗号分隔开

最好是在编译或设计时就知道值的所有类型, 比如上面的方向, 当然后面也可以增加

2 枚举的本质

枚举在编译时, 编译器会将其编译为 Java 中 java.lang.Enum 的子类。

我们将上面的 DirectionEnum 进行反编译, 可以获得如下的代码:

// final:无法继承 public final class DirectionEnum extends Enum { // 在之前定义的实例 public static final DirectionEnum EAST; public static final DirectionEnum WEST; public static final DirectionEnum NORTH; public static final DirectionEnum SOUTH; private static final DirectionEnum $VALUES[]; // 编译器添加的 values() 方法 public static DirectionEnum[] values() { return (DirectionEnum[])$VALUES.clone(); } // 编译器添加的 valueOf 方法, 调用父类的 valueOf 方法 public static DirectionEnum valueOf(String name) { return (DirectionEnum)Enum.valueOf(cn/homejim/java/lang/DirectionEnum, name); } // 私有化构造函数, 正常情况下无法从外部进行初始化 private DirectionEnum(String s, int i) { super(s, i); } // 静态代码块初始化枚举实例 static { EAST = new DirectionEnum("EAST", 0); WEST = new DirectionEnum("WEST", 1); NORTH = new DirectionEnum("NORTH", 2); SOUTH = new DirectionEnum("SOUTH", 3); $VALUES = (new DirectionEnum[] { EAST, WEST, NORTH, SOUTH }); } }

通过以上反编译的代码, 可以发现以下几个特点

2.1 继承 java.lang.Enum

通过以上的反编译, 我们知道了, java.lang.Enum 是所有枚举类型的基类。查看其定义

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {

可以看出来, java.lang.Enum 有如下几个特征

抽象类, 无法实例化

实现了 Comparable 接口, 可以进行比较

实现了 Serializable 接口, 可进行序列化

因此, 相对应的, 枚举类型也可以进行比较和序列化

2.2 final 类型

final 修饰, 说明枚举类型是无法进行继承的

2.3 枚举常量本身就是该类的实例对象

可以看到, 我们定义的常量, 在类内部是以实例对象存在的, 并使用静态代码块进行了实例化。

2.4 构造函数私有化

不能像正常的类一样, 从外部 new 一个对象出来。

2.5 添加了 $values[] 变量及两个方法

$values[]: 一个类型为枚举类本身的数组, 存储了所有的示例类型

values() : 获取以上所有实例变量的克隆值

valueOf(): 通过该方法可以通过名称获得对应的枚举常量

3 枚举的一般使用

枚举默认是有几个方法的

3.1 类本身的方法

从前面我的分析, 我们得出, 类本身有两个方法, 是编译时添加的

3.1.1 values()

先看其源码

public static DirectionEnum[] values() { return (DirectionEnum[])$VALUES.clone(); }

返回的是枚举常量的克隆数组。

使用示例

@Test public void testValus() { DirectionEnum[] values = DirectionEnum.values(); for (DirectionEnum direction: values) { System.out.println(direction); } }

输出

EAST WEST NORTH SOUTH 3.1.2 valueOf(String)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzwgx.html