Java魔法堂:枚举类型详解
一、前言
Java的枚举类型相对C#来说具有更灵活可配置性,Java的枚举类型可以携带更多的信息。
// C#
enum MyColor{
RED = ,
BLUE =
}
Console.Write(MyColor.RED); // Java
enum MyColor{
RED("Hot", ), BLUE("SAD",); private String mood;
public String getMood{
return mood;
}
private int index;
public int getIndex(){
return index;
}
private MyColor(String mood, int index){
this.mood = mood;
this.index = index;
}
}
System.out.println(MyColor.RED.getMood());
本文将对枚举类型进行较为详细的叙述,以便日后查阅。
二、最简单的用法——常量
/* 定义 */
// 形式1
enum MyColor{
RED,BLUE
} // 形式2
enum MyColor{
RED,BLUE;
} /* 使用 */
System.out.println(MyColor.RED.name()); // 显示RED
System.out.println(MyColor.RED.ordinal()); // 显示0
System.out.println(MyColor.BLUE.name()); // 显示BLUE
System.out.println(MyColor.BLUE.ordinal()); // 显示1
枚举值的name()会返回枚举值的字面量,而ordinal()为返回枚举值的索引,而索引是以枚举值定义时的位置来确定,并在编译时设置的。下面我们来看看到底编译器为我们做了什么?
final class MyColor extends java.lang.Enum<MyCorlor>{
public static final MyColor RED;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final MyColor BLUE;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static MyColor[] values();
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=, locals=, args_size=
: getstatic # // Field $VALUES:[LMyColor;
: invokevirtual # // Method "[LMyColor;".clone:()Ljava/lang/Object;
: checkcast # // class "[LMyColor;"
: areturn
LineNumberTable:
line :
public static MyClass valueOf(java.lang.String);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=, locals=, args_size=
: ldc_w # // class MyColor
: aload_0
: invokestatic # // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
: checkcast # // class MyColor
: areturn
LineNumberTable:
line :
static {};
flags: ACC_STATIC
Code:
stack=, locals=, args_size=
: new # // class MyColor
: dup
: ldc # // String RED
: iconst_0
: invokespecial # // Method "<init>":(Ljava/lang/String;I)V
: putstatic # // Field RED:LMyColor;
: new # // class MyColor
: dup
: ldc # // String BLUE
: iconst_1
: invokespecial # // Method "<init>":(Ljava/lang/String;I)V
: putstatic # // Field BLUE:LMyColor;
: iconst_2
: anewarray # // class MyColor
: dup
: iconst_0
: getstatic # // Field RED:LMyColor;
: aastore
: dup
: iconst_1
: getstatic # // Field BLUE:LMyColor;
: aastore
: putstatic # // Field $VALUES:[LMyColor;
: return
LineNumberTable:
line :
line : 26
}
可以看到编译器将enum MyColor编译为一个继承Enum<MyColor>并且带修饰符final的MyColor类。
而枚举值RED和BLUE则被编译为MyColor的类常量,并且在类加载的初始化阶段实例化。MyColor默认的构造函数会调用父类Enum<MyColor>的构造函数Enum<E>(String name, int ordinal)来设置私有字段name和ordinal的值。其中iconst_0和iconst_1分别表示将0和1压栈,invokespecial #8则是调用构造函数Enum<E>(String name, int ordinal)。
: new # // class MyColor
: dup
: ldc # // String RED
: iconst_0 // int 0
: invokespecial # // Method "<init>":(Ljava/lang/String;I)V
: putstatic # // Field RED:LMyColor;
: new # // class MyColor
: dup
: ldc # // String BLUE
: iconst_1 // int 1
: invokespecial # // Method "<init>":(Ljava/lang/String;I)V
: putstatic # // Field BLUE:LMyColor;
另外在类加载的初始化阶段会生成一个私有的$VALUE数组用于存放常量RED和BLUE,而在调用MyColor.values()返回的正是这个$VALUE数组的复制品。
: iconst_2
: anewarray # // class MyColor
: dup
: iconst_0
: getstatic # // Field RED:LMyColor;
: aastore
: dup
: iconst_1
: getstatic # // Field BLUE:LMyColor;
: aastore
: putstatic # // Field $VALUES:[LMyColor;
小结:
1. 定义枚举类型本质上就是在定义带final修饰符的Enum<E>的子类;
2. 枚举值本质为第1点所定义的类的类常量;
3. 枚举值的ordinal值由其定义时的排序决定,并且在编译时已经被设置好了。
三、枚举类型的抽象父类Enum<E>
其实我们大多数情况下都是调用父类Enum<E>的方法来操作自定义的枚举值,下面一起看看父类Enum<E>吧!
1. 它为抽象类且继承了Comparable<E>和Serializable两个类。
2. 内含私有字段name和ordinal和对应的公有get方法name()和ordinal()。
3. 重写了equals方法,通过==比较两个枚举值的内存地址来判断两者是否相同。
4. 实现compareTo方法,通过比较两个枚举值的ordinal值来做判断。
5. getDeclaringClass方法,用于返回枚举的Class对象。
四、携带更多信息——自定义构造函数
由于枚举最终被编译为类,因此我们通过自定义构造函数、自定义字段和方法来让枚举值携带更多信息
public enum MyColor{
RED("Hot", ), BLUE("SAD",);
private String mood;
private int index;
private MyColor(String mood, int index){
this.mood = mood;
this.index = index;
}
}
注意:
1. 自定义的构造函数必须是私有的;
2. 构造函数内不能显式调用父类的构造函数;
3. RED、BLUE的ordinal值依然是0和1,那么值依然是RED和BLUE。
上述3点规定和结果的原因是编译器会对我们的自定义构造函数进行加工变为
private MyColor(String name, String ordinal, String mood, int index){
super(name, ordinal);
this.mood = mood;
this.index = index;
}
五、让相同枚举类型下的枚举值具有不同的行为——重写枚举值的方法
public enum MyColor{
RED, BLUE(){
@Override
public boolean getFlag(){
return false;
}
};
public boolean getFlag(){
return true;
}
}
// 调用
System.out.println(MyColor.RED.getFlag()); // 显示true
System.out.println(MyColor.BLUE.getFlag()); // 显示false
可以看到枚举值RED和BLUE同一个方法具有不同的行为。其实这是通过匿名内部类的方式实现的,BLUE的类型为MyColor$1 extends MyColor,而RED的类型为MyColor。
六、使用接口组织枚举
public interface Food {
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO
}
enum Dessert implements Food {
FRUIT, CAKE, GELATO
}
}
七、总结
若有纰漏请大家指正,谢谢。
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4297741.html ^_^肥仔John
八、参考
http://www.tuicool.com/articles/YvQZFf
http://www.cnblogs.com/hemingwang0902/archive/2011/12/29/2306263.html
http://www.cnblogs.com/frankliiu-java/archive/2010/12/07/1898721.html
Java魔法堂:枚举类型详解的更多相关文章
- Java中的枚举类型详解
枚举类型介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常量的定义 ...
- Java魔法堂:内部类详解
一.前言 对于内部类平时编码时使用的场景不多,比较常用的地方应该就是绑定事件处理程序的时候了(从C#.JS转向Java阵营的孩子总不不习惯用匿名内部类来做事件订阅:().本文将结合Bytecode对四 ...
- Java中的枚举使用详解
转载至:http://www.cnblogs.com/linjiqin/archive/2011/02/11/1951632.html package com.ljq.test; /** * 枚举用法 ...
- java枚举类型详解
枚举类型是JDK1.5的新特性.显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类.而这些类都是类库中Enum类的子类(java.lang.Enum<E>).它 ...
- MyBatis魔法堂:ResultMap详解
一.前言 MyBatis是基于“数据库结构不可控”的思想建立的,也就是我们希望数据库遵循第三范式或BCNF,但实际事与愿违,那么结果集映射就是MyBatis为我们提供这种理想与现实间转换的手段了, ...
- C语言--enum,typedef enum 枚举类型详解
原文:http://z515256164.blog.163.com/blog/static/32443029201192182854300/ 有改动 C语言详解 - 枚举类型 注:以下全部代码的执行环 ...
- 测者的测试技术手册:Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)
Enum的简介 枚举类型很早就在计算机语言中存在了,主要被用来将一组相似的值包含进一种类型中,这种类型的名称被定义成独一无二的类型描述符,这就是枚举类型. 在java语言中,枚举类型是一个完整功能的类 ...
- C++枚举类型详解
原创作品,转载请注明来源:http://www.cnblogs.com/shrimp-can/p/5171110.html 一.枚举类型的定义 enum 类型名 {枚举值表}: 类型名是变量名,指定 ...
- 转载 - C - 枚举类型详解
出处:http://www.cnblogs.com/JCSU/articles/1299051.html 注:以下全部代码的执行环境为VC++ 6.0 在程序中,可能需要为某些整数定义一个别名,我们可 ...
随机推荐
- 如何禁用Marlin温度保护
最近在玩3D打印,搞了套MEGA 2560 + RAMPS 1.4 + A4988,刷Marlin(https://github.com/MarlinFirmware/Marlin)固件,接上电机调试 ...
- Android Scroll分析——滑动效果产生
相对于在Android2.x版本上出现的长按.点击事件的效果,不得不说,滑动操作具有更好的用户体验.因此,从Android 4.X版本开始,出现了更多滑动操作的效果.越来越多第三方应用模仿这样的效果, ...
- .Net Core开源通讯组件 SmartRoute(服务即集群)
SmartRoute是基于Dotnet Core设计的可运行在linux和windows下的服务通讯组件,其设计理念是去中心化和零配置即可实现服务通讯集群.SmartRoute是通过消息订阅的机制实现 ...
- SQL Server 常用分页SQL
今天无聊和朋友讨论分页,发现网上好多都是错的.网上经常查到的那个Top Not in 或者Max 大部分都不实用,很多都忽略了Order和性能问题.为此上网查了查,顺带把2000和2012版本的也补上 ...
- 学习设计模式第三 - 基础使用UML表示关系
面向对象的思想中存在如下几种关系,一般为了方便交流都使用UML的类图来展现类之间的关系.所以了解类图中符号的含义对看懂类图,尤其是用类图展示的设计模式很有帮助.下面依次介绍这几种关系 类继承关系 继承 ...
- 千万用户级别应用系统背后的SOA组件化容器
背景 在<我们的应用系统是如何支撑千万级别用户的>随笔中已经从“宏观”角度去介绍了整个应用系统的布局.组件化是整个系统由头到尾都始终坚持的一个设计原则,其中“SOA组件化容器”也是我们应用 ...
- 【吉光片羽】MVC 导出Word的两种方式
1.直接将Html转成Word.MVC自带FileResult很好用.Html中我们也可以嵌入自己的样式. html: <div id="target"> <st ...
- Linux grep命令和正则表达式
介绍 grep是一个功能强大的文本搜索命令,可以用它来搜索某个文件中是否包含指定的搜索内容,它可以利用正则表达式来做复杂的筛选操作,它还可以为其它命令传输给管道的筛选,比如我们常用到的分析单个进程的操 ...
- Qt 设置应用程序图标
Qt4设置应用程序图标 将一个ico图标放在资源文件夹下; 然后建立txt,输入 IDI_ICON1 DISCARABLE "myico.ico"; 保存文件,将其后缀改为.rc; ...
- RSS与公众号
这次怀念下曾经火热的RSS.RSS是我很喜欢的一种看信息学习的方式,但是这项技术随着谷歌reader产品的停止已经陨落了.之后再无给力的客户端,无法让人愉悦的使用.我也曾尝试用鲜果,有道等国内产品,由 ...