Java Enum的使用和深入理解
2015-09-21 01:39
726 查看
参考:
Java enum的用法详解Java 1.5新特性Enum的学习和使用
1、Enum的使用
请参考:Java enum的用法详解详细介绍了enum的一下几个用法:
用法一:常量;
用法二:switch;
用法三:向枚举中添加新方法;
用法四:覆盖枚举的方法;
用法五:实现接口;
用法六:使用接口组织枚举;
用法七:关于枚举集合的使用;
枚举和常量定义的区别;
注意:在case标签中,枚举前缀不能出现,即case Color.RED是不合法的,只能直接用枚举值RED。而在其他地方出现时则必须用Color.RED。
2、深入理解Enum
2.1 首先看看最简单的enum用法:public class EnumMonth { public static void main(String[] args) { for (Month month : Month.values()) { System.out.println(month); } } private enum Month { JAN, SEP, MAR, APR, MAY; } }结果:
JAN SEP MAR APR MAY
2.2 使用javap EnumMonth$Month看到反编译的结果,Month会被编译成一个Java类:
Compiled from "EnumMonth.java" final class com.demo.mytest.enumTest.EnumMonth$Month extends java.lang.Enum<com.demo.mytest.enumTest.EnumMonth$Month> { public static final com.demo.mytest.enumTest.EnumMonth$Month JAN; public static final com.demo.mytest.enumTest.EnumMonth$Month SEP; public static final com.demo.mytest.enumTest.EnumMonth$Month MAR; public static final com.demo.mytest.enumTest.EnumMonth$Month APR; public static final com.demo.mytest.enumTest.EnumMonth$Month MAY; public static com.demo.mytest.enumTest.EnumMonth$Month[] values(); public static com.demo.mytest.enumTest.EnumMonth$Month valueOf(java.lang.String); static {}; }1. 这个Month枚举类是final class,即不能被继承,而它本身是继承于Enum;
2. 这些枚举值是Month对象,而且是static final修饰的;
3. 注意values()方法,它能得到所有的枚举值,但这方法在Enum里面没有找到,在看到反编译结果后才确认的。
2.3 valueOf(String)方法和static静态块
valueOf(String)方法,返回带指定名称的指定枚举类型的枚举常量。
在使用javap -c EnumMonth$Month进一步查看汇编代码后,知道原来是调用Enum.valueOf(Class<T> enumType, String name):
public static com.demo.mytest.enumTest.EnumMonth$Month valueOf(java.lang.String); Code: 0: ldc_w #4 // class com/demo/mytest/enumTest/EnumMonth$Month 3: aload_0 4: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; 7: checkcast #4 // class com/demo/mytest/enumTest/EnumMonth$Month 10: areturnstatic{}里面主要是new这些枚举值对象:
static {}; Code: 0: new #4 // class com/demo/mytest/enumTest/EnumMonth$Month 3: dup 4: ldc #7 // String JAN 6: iconst_0 7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #9 // Field JAN:Lcom/demo/mytest/enumTest/EnumMonth$Month; 13: new #4 // class com/demo/mytest/enumTest/EnumMonth$Month 16: dup 17: ldc #10 // String SEP 19: iconst_1 20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 23: putstatic #11 // Field SEP:Lcom/demo/mytest/enumTest/EnumMonth$Month; 26: new #4 // class com/demo/mytest/enumTest/EnumMonth$Month
2.4看一下enum类:
package java.lang; import java.io.Serializable; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamException; public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { private final String name; public final String name() { return name; }
private final int ordinal; public final int ordinal() { return ordinal; } protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; }
public String toString() { return name; } public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { T result = enumType.enumConstantDirectory().get(name); if (result != null) return result; if (name == null) throw new NullPointerException("Name is null"); throw new IllegalArgumentException( "No enum constant " + enumType.getCanonicalName() + "." + name); } <span style="white-space:pre"> </span>//........其他方法 }这里要说说Enum的构造函数Enum(String name, int ordinal),形参name就是枚举值的string形式("JAN"),ordinal值则是编译器按照枚举值的顺序从0排着赋值的。要注意,这个ordinal值原来是不能改变的,即编译器是从0升序赋值的,在字节码里面固定写着iconst_0(n=0,1,2...)的。
static{ JAN = new EnumMonth$Month("JAN", 0); SEP = new EnumMonth$Month("SEP", 1); ... }于是Enum里面的String name()和int ordinal()方法就是返回这两个值的。
Enum.toString()也是返回name值,这就是为什么System.out.println(month);会输出那些值。
看看下面的例子:
public class EnumMonth { public static void main(String[] args) { for (Month month : Month.values()) { System.out.println(month.ordinal()); } } private enum Month { JAN(1), SEP(9), MAR(3), APR(4), MAY(5); final int id; Month(int id){ this.id = id; } } }一开始没有加上id成员变量和构造函数的,编译时提示找不到构造函数 Month(int),本以为JAN(1)的1会赋值给形参ordinal呢!修正后,运行结果是:
0 1 2 3 4说明ordinal值是固定不变的。
查看汇编代码:
0: new #4; //class EnumMonth$Month 3: dup 4: ldc #8; //String JAN 6: iconst_0 7: iconst_1 8: invokespecial #9; //Method "<init>":(Ljava/lang/String;II)V 11: putstatic #10; //Field JAN:LEnumMonth$Month;这时发现构造函数似乎增加一个形参int类型id。
我再尝试把int id改为char,运行结果是一样的:
private enum Month { JAN('1'), SEP('9'), MAR('3'), APR('4'), MAY('5'); final char id; Month(char id){ this.id = id; } }但编译代码有所不同:
0: new #4; //class EnumMonth$Month 3: dup 4: ldc #8; //String JAN 6: iconst_0 7: bipush 49 9: invokespecial #9; //Method "<init>":(Ljava/lang/String;IC)V 12: putstatic #10; //Field JAN:LEnumMonth$Month;所以个人认为,如果我们添加了自定义的构造函数,编译器会自动构建新的构造函数:
Enum(String name, int ordinal, char id) { super(name, ordinal); //copy 自定义构造函数的内容 this.id = id; }注意:构造器只能私有private,绝对不允许有public构造器。否则提示modifier public not allowed here。
相关文章推荐
- JAVA基础--db06_java面向对象-二维数组
- 关于Java虚拟机性能调优方法的一些分析
- Java学习之Iterator(迭代器)的一般用法
- Win7下配置java环境变量
- java中的反射
- spring security学习笔记
- SpringMvc-restFul学习笔记
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- JAVA编程基础(一)
- Spring注解整合(hibernate+mybatis) 学习笔记
- Java中long和Long有什么区别(转)
- SpringMvc学习笔记一
- Spring+hibernate整合学习笔记-2
- 使用IntelliJ IDEA,gradle开发Java web应用步骤
- Spring-Hibernate整合 学习笔记
- Spring-AOP学习笔记
- Spring入门-学习笔记
- Java Mybatis框架入门基础教程
- java 连接sql server2008数据库配置
- 【MyBatis框架】mybatis和spring整合