语法糖
Java 从 JDK1.5 开始支持枚举, 也就是说, Java 一开始是不支持枚举的, 就像泛型一样, 都是 JDK1.5 才加入的新特性. 通常一个特性如果在一开始没有提供, 在语言发展后期才添加, 会遇到一个问题, 就是向后兼容性的问题. 像 Java 在 1.5 中引入的很多特性, 为了向后兼容, 编译器会帮我们写的源代码做很多事情, 比如泛型为什么会擦除类型, 为什么会生成桥接方法, foreach 迭代, 自动装箱/拆箱等, 这有个术语叫 "语法糖", 而编译器的特殊处理叫 "解语法糖". 那么像枚举也是在 JDK1.5 中才引入的, 又是怎么实现的呢?
本质
一个枚举在经过编译器编译过后, 变成了一个抽象类, 它继承了 java.lang.Enum
; 而枚举中定义的枚举常量, 变成了相应的 public static final
属性, 而且其类型就抽象类的类型, 名字就是枚举常量的名字, 同时我们可以在 Operator.class 的相同路径下看到四个内部类的.class 文件:
- com/mikan/Operator$1.class
- com/mikan/Operator$2.class
- com/mikan/Operator$3.class
- com/mikan/Operator$4.class
也就是说这四个命名字段分别使用了内部类来实现的; 同时添加了两个方法 values()
和 valueOf(String)
. 我们定义的构造方法本来只有一个参数, 但却变成了三个参数;同时还生成了一个静态代码块.
其实编译器生成的这个静态代码块做了如下工作:
- 分别设置生成的四个公共静态常量字段的值
- 编译器还生成了一个静态字段$VALUES, 保存的是枚举类型定义的所有枚举常量
构造方法为什么增加了两个参数?
有一个问题, 构造方法我们明明只定义了一个参数, 为什么生成的构造方法是三个参数呢?
从 Enum 类中我们可以看到, 为每个枚举都定义了两个属性, name 和 ordinal, name 表示我们定义的枚举常量的名称, 如 ADD
, SUBTRACT
等, 而 ordinal 是一个顺序号, 根据定义的顺序分别赋予一个整形值, 从 0 开始. 在枚举常量初始化时, 会自动为初始化这两个字段, 设置相应的值, 所以才在构造方法中添加了两个参数. 即:
com.mikan.Operator$1(String name, int ordinal, String operator);
文章评论