A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© justin1258 中级黑马   /  2014-8-5 22:58  /  1765 人查看  /  10 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 justin1258 于 2014-8-6 10:43 编辑

Java SE5新增了枚举类型,为我们编写程序提供了很大的方便。在jdk 1.5之前,程序员定义类似星期这一类具有枚举特点的数据类型时会采用一些自定义的方式,比如下面的代码:
代码段一:
  1. final class WeekDay{
  2.     public static final int SUN = 0;
  3.     public static final int TUE = 1;
  4.     public static final int WED = 2;
  5.     //others...
  6. }
复制代码
代码段二:
  1. final class WeekDay{
  2.     public static final WeekDay SUN = new WeekDay();
  3.     public static final WeekDay TUE = new WeekDay();
  4.     public static final WeekDay WEN = new WeekDay();
  5.     // others...
  6.     private WeekDay(){};
  7. }
复制代码
上面两段代码能在一定程度上解决问题。第一段代码可以解决纯数字带来的歧义,但是有安全隐患,因为枚举值很容易被改动,比如SUN改为1TUE改为0,而编译器检测不出这一点。第二段代码看似是一个不错的解决方案,但是最大的缺陷是不能支持switch语句。可见自定义的枚举类型并不能完全地解决问题,而且不同的编程人员之间必须达成编码协议。所以jdk1.5支持了枚举类型,使编程人员可以以一致的方式定义枚举类型。下面就总结一下java的枚举类型。

枚举的实现方式

用enum关键字定义枚举类型非常简洁:
  1. enum WeekDay{
  2.     SUN, TUE, MON, WEN, THU, FRI, SAT;
  3. }
复制代码
可以用javap工具查看编译后的字节码,上面的代码基本等价于下面的代码:
  1. class WeekDay extends Enum<WeekDay>{
  2.     public static final WeekDay SUN = new WeekDay("SUN", 0);
  3.     public static final WeekDay TUE = new WeekDay("TUE", 1);
  4.     public static final WeekDay MON = new WeekDay("MON", 2);
  5.     // others...
  6.     private static final WeekDay[] ENUM$VALUES;
  7.    
  8.     static{
  9.         ENUM$VALUES = new WeekDay[7];
  10.         ENUM$VALUES[0] = SUN;
  11.         ENUM$VALUES[1] = TUE;
  12.         ENUM$VALUES[2] = MON;
  13.         // others...
  14.     }
  15.    
  16.     private WeekDay(String name, int ordinal){
  17.         super(name, ordinal);
  18.     }
  19.    
  20.     public static WeekDay[] values() {
  21.         WeekDay[] values = new WeekDay[7];
  22.         System.arraycopy(ENUM$VALUES, 0, values, 0, 7);
  23.         return values;
  24.     }
  25.    
  26.     public static WeekDay valueOf(String name) {
  27.         return Enum.valueOf(WeekDay.class, name);
  28.     }
  29. }
复制代码
上面的代码不能通过编译,这只是编译器对枚举类型编译后的字节码的还原,方便理解。从上面的还源代码可以总结出一下几点:

1.      用enum定义的枚举类型其实是一个普通的类,并且继承自Enum<E>;
2.      编译后的枚举类的构造函数为私有,这样外界就不能随意构造枚举对象;
3.      每一个枚举值其实是一个枚举类的对象,并且声明为静态常量;
4.      枚举类的基类维护两个字段:name和ordinal,前者为枚举值对应名称的字符串,后者为每一个枚举值对应的序号。这两个值在构造每一个枚举值对象的时候传进构造函数;
5.      枚举类型多了两个静态方法values和valueOf,前者以数组的方式返回所有枚举值,后者根据字符串返回对应的枚举值;
6.      当只有一个枚举值的时候,枚举类其实就是一个实现单例模式的类,所以为了方便可以以枚举的方式定义一个单例类(不建议哦);

在枚举中定义其他成员

1.      定义自定义构造函数
枚举可以定义私有构造函数,并在定义枚举值的时候指定调用某个构造函数:
  1. enum WeekDay{
  2.     SUN("Sunday"), TUE, MON, WEN, THU, FRI, SAT;
  3.    
  4.     private String fullName;
  5.     private WeekDay(){}
  6.     private WeekDay(String fullName){
  7.         this.fullName = fullName;
  8.     }
  9. }
复制代码
其实编译器会在每个构造函数的参数列表前面加上一个String和int类型的参数,用来传递name和ordinal两个值。

2.      枚举类型可以定义方法
在枚举类型中可以定义任何方法:
  1. enum WeekDay{
  2.     SUN(){
  3.         public WeekDay nextDay() {
  4.             return TUE;
  5.         }
  6.     },
  7.     TUE(){
  8.         public WeekDay nextDay() {
  9.             return MON;
  10.         }
  11.     }
  12.     //others...
  13.     ;
  14.    
  15.     public abstract WeekDay nextDay();
  16. }
复制代码
这种方式虽然很方便很灵活,但是有个缺点就是会产生很多class文件,比如上面的一个类就要产生8个class文件。

三 枚举的优点
1.      语法简洁;
2.      类型安全;
3.      支持switch语句;
4.      不受反射和反序列化的破坏;

java枚举解析.rar

16.07 KB, 下载次数: 243

word附件

点评

是嘛~~再接再厉~  发表于 2014-8-6 15:48

评分

参与人数 1技术分 +1 收起 理由
格子、 + 1 笔记总结的不是很全面哦

查看全部评分

10 个回复

倒序浏览
学习了 ,,,
回复 使用道具 举报
为什么不建议用枚举实现单例?我看到有些文章推荐的,我自己也觉得不错
回复 使用道具 举报
fantacyleo 发表于 2014-8-5 23:21
为什么不建议用枚举实现单例?我看到有些文章推荐的,我自己也觉得不错

是吗?额,我没有看过相关文章,只是觉得如果用的话可能会引起歧异。
回复 使用道具 举报
justin1258 发表于 2014-8-5 23:30
是吗?额,我没有看过相关文章,只是觉得如果用的话可能会引起歧异。

Effective Java这本书就推荐过。枚举单例是线程安全的而且不受反射和反序列化的破坏,不过无法延迟初始化就是了
回复 使用道具 举报
fantacyleo 发表于 2014-8-5 23:42
Effective Java这本书就推荐过。枚举单例是线程安全的而且不受反射和反序列化的破坏,不过无法延迟初始化 ...

我刚试了一下,确实不受序列化影响。然后反射它是会报运行时异常是吧?
回复 使用道具 举报
justin1258 发表于 2014-8-6 10:13
我刚试了一下,确实不受序列化影响。然后反射它是会报运行时异常是吧? ...

是的。NoSuchMethodException
回复 使用道具 举报
学习了!!!!!!
回复 使用道具 举报
:#是嘛~~再接再厉~
回复 使用道具 举报
赞一个~~~~~
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马