文档章节

Enum到底是何方神圣

牧师-Panda
 牧师-Panda
发布于 2017/04/27 16:50
字数 1624
阅读 19
收藏 0

Enum是在java 1.5这个版本引入的, 存放于java.lang中,它是所有java枚举类型的基本类。

它的最大的一个作用就是,定义表示一组相同类型常量

与传统的常量定义的区别

 Public static class RainbowColor { 
    // 红橙黄绿青蓝紫七种颜色的常量定义
    public static final int RED = 0; 
    public static final int ORANGE = 1; 
    public static final int YELLOW = 2; 
    public static final int GREEN = 3; 
    public static final int CYAN = 4; 
    public static final int BLUE = 5; 
    public static final int PURPLE = 6; 
 }
public class State {
    public static final int ON = 1;
    public static final int OFF= 0;
}

如上图所示,我们习惯了在接口或者是在类里面对常量进行定义,使用的时候,你可以在程序中直接引用这些常量。但是,这种方式还是存在着一些问题。

类型不安全

由于颜色常量的对应值是整数形,所以程序执行过程中很有可能给颜色变量传入一个任意的整数值,导致出现错误。

没有命名空间

由于颜色常量只是类的属性,当你使用的时候不得不通过类来访问。

一致性差

因为整形枚举属于编译期常量,所以编译过程完成后,所有客户端和服务器端引用的地方,会直接将整数值写入。这样,当你修改旧的枚举整数值后或者增加新的枚举值后,所有引用地方代码都需要重新编译,否则运行时刻就会出现错误。

类型无指意性

由于颜色枚举值仅仅是一些无任何含义的整数值,如果在运行期调试时候,你就会发现日志中有很多魔术数字,但除了程序员本身,其他人很难明白其奥秘。

而enum类型的定义方式可能让有些朋友颇为不习惯,有时候让人觉得它就像是关键字class,又让人觉得它是一种嵌套在类里面的符合方法,我们先来看一看enum的语法是怎么定义的:

创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类
(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum<E extends Enum<E>>,
而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 
构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。

因此我们写一段代码来看看这个语法是什么意思:

public enum EnumTest {
    MON, TUE, WED, THU, FRI, SAT, SUN;
}

这段代码实际上是实现了以下过程:

new Enum<EnumTest>("MON",0);
new Enum<EnumTest>("TUE",1);
new Enum<EnumTest>("WED",2);

enum常量类型常量的使用有以下好处:

  • 用enum常量说明的常量由编译程序自动生成,程序员不需要对常量进行手工赋值。
  • 可以保证单例模式,且比较时候可以用 ”==” 来替换 equals

enum类型的使用例子

遍历,switch

public class Test {
    public static void main(String[] args) {
        for (EnumTest e : EnumTest.values()) {
            System.out.println(e.toString());
        }
         
         
        EnumTest test = EnumTest.TUE;
        switch (test) {
        case MON:
            System.out.println("今天是星期一");
            break;
        case TUE:
            System.out.println("今天是星期二");
            break;
        // ... ...
        default:
            System.out.println(test);
            break;
        }
    }
}

EnumSet,EnumMap 的应用

public class Test {
    public static void main(String[] args) {
        // EnumSet的使用
        EnumSet<EnumTest> weekSet = EnumSet.allOf(EnumTest.class);
        for (EnumTest day : weekSet) {
            System.out.println(day);
        }
 
        // EnumMap的使用
        EnumMap<EnumTest, String> weekMap = new EnumMap(EnumTest.class);
        weekMap.put(EnumTest.MON, "星期一");
        weekMap.put(EnumTest.TUE, "星期二");
        // ... ...
        for (Iterator<Entry<EnumTest, String>> iter = 
weekMap.entrySet().iterator(); iter.hasNext();) {
            Entry<EnumTest, String> entry = iter.next();
            System.out.println(entry.getKey().name() + ":" + entry.getValue());
        }
    }
}

 

enum类型注意事项

  1. enum 类型不支持 public 和 protected 修饰符的构造方法,因此构造函数一定要是 private 或 friendly 的。也正因为如此,所以枚举对象是无法在程序中通过直接调用其构造方法来初始化的。这一特点保证了其单例模式和类型安全。
  2. 定义 enum 类型时候,如果是简单类型,那么最后一个枚举值后不用跟任何一个符号;但如果有定制方法,那么最后一个枚举值与后面代码要用分号';'隔开,不能用逗号或空格。
  3. 由于 enum 类型的值实际上是通过运行期构造出对象来表示的,所以在 cluster 环境下,每个虚拟机都会构造出一个同义的枚举对象。因而在做比较操作时候就需要注意,如果直接通过使用等号 ( ‘ == ’ ) 操作符,这些看似一样的枚举值一定不相等,因为这不是同一个对象实例
  4. 它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。 
  5. 所有枚举值都是public , static , final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。 
  6. Enum默认实现了java.lang.Comparable接口。 
  7. Enum覆载了了toString方法,因此我们如果调用Color.Blue.toString()默认返回字符串”Blue”. 
  8. Enum提供了一个valueOf方法,这个方法和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue.因此我们在自己重写toString方法的时候就要注意到这一点,一把来说应该相对应地重写valueOf方法。 
  9. Enum还提供了values方法,这个方法使你能够方便的遍历所有的枚举值。 
  10. Enum还有一个oridinal的方法,这个方法返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。

enum类型的原理

上文中已经说了,enum类型跟我们平时用的关键字class有点儿类似,你可以把它理解成另类的class,我们通过反编译代码可以看到如下的结果:

public class com.hmw.test.EnumTest extends java.lang.Enum{
    public static final com.hmw.test.EnumTest MON;
    public static final com.hmw.test.EnumTest TUE;
    public static final com.hmw.test.EnumTest WED;
    public static final com.hmw.test.EnumTest THU;
    public static final com.hmw.test.EnumTest FRI;
    public static final com.hmw.test.EnumTest SAT;
    public static final com.hmw.test.EnumTest SUN;
    static {};
    public int getValue();
    public boolean isRest();
    public static com.hmw.test.EnumTest[] values();
    public static com.hmw.test.EnumTest valueOf(java.lang.String);
    com.hmw.test.EnumTest(java.lang.String, int, int, com.hmw.test.EnumTest);
}

所以事实证明,enum确实是一个类。

最后,这篇博客讲的也很好,我从中收益良多,推荐给大家。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

牧师-Panda
粉丝 32
博文 146
码字总数 180044
作品 0
浦东
私信 提问
EECHEN是什么来头的?

关注了很久eechen的发言。 貌似他对IT理解比较深刻, 是国产化的死忠党。 不知道他到底是何方神圣?

修改登录密码
2015/04/26
3K
11
liongliong、accpt是CSDN的何方神圣?

根据从www.csdn.net.sql文件上的分析,拥有个人用户账号最多的会员是名叫liongliong的,还有个accpt,其用liongliongX(X为数字)一共注册了上千个账户,例:liongliong314、liongliong315、...

咖啡碼農
2011/12/22
311
6
Windows10 手机应用程序开发 - 2. 第一个Hello World程序

目标:在手机屏幕上增加一个Button,通过点击Button向输出窗口输出Hello World 字符串。 1、先分析一下VS界面上的解决方案管理器中各个文件夹下的文件到底是何方神圣 ├ HelloWorld·····...

神补刀
2016/01/16
210
0
从 for of 聊到 Generator

你能学到什么 对 更深入的理解 到底是何方神圣? 数组也是对象,为什么不能用 来遍历对象呢? 如何实现对象的 ? 又是何方神圣? 有什么用呢? 聊聊 说起 相信每个写过 的人都用过 ,平时我们用...

Jack088
01/17
0
0
1521端口被占用的问题

不知道为什么,总碰到奇葩问题,这两天用toad连数据库,toad直接死掉,然后tomcat也开不起来了,报获取数据库连接的错误,昨天重装了oracle,好了一天,今天又不行了,进数据库日志看了下,报...

looqy
2015/01/02
855
2

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 程序员做噩梦

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# 手嶌葵《Kiss The Girl》 《Kiss The Girl》- 手嶌葵 手机党少年们想听歌,请使劲儿戳(这里) @Sharon啊 :今天...

小小编辑
27分钟前
62
2
Another app is currently holding the yum lock; waiting for it to exit...

Another app is currently holding the yum lock; waiting for it to exit... The other application is: PackageKit Memory : 153 M RSS (266 MB VSZ) Started: Thu Jul 12 00:03......

圣洁之子
35分钟前
0
0
FastDateFormat 研究

FastDateFormat 对缓存的利用,其实就是用ConcurrentHashMap 做了一个map类型的缓存 public F getInstance(final String pattern, TimeZone timeZone, Locale locale) { Validate......

暗中观察
今天
3
0
Android双向绑定原理简述

Android双向绑定原理简述 双向绑定涉及两个部分,即将业务状态的变化传递给UI,以及将用户输入信息传递给业务模型。 首先我们来看业务状态是如何传递给UI的。开启dataBinding后,编译器为布局...

tommwq
今天
4
0
Spring系列教程八: Spring实现事务的两种方式

一、 Spring事务概念: 事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。...

我叫小糖主
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部