学习笔记:java枚举
2017-11-30 11:31
253 查看
java自1.5后支持枚举。Java中,枚举的本质是一种类,Java在其上做了很多特殊的约束,这也使得枚举具备了简洁、安全和便捷的特性。
一、Java枚举(enum)的定义。
Java5之前,没有枚举,定义常量的常见方式是这样的:
这种定义方式没错,但是存在以下几点不足:
1、存在类型安全隐患。看下面代码:
方法的参数是int型,即任何的int类型的值不限1、0、-1都能够作为该方法的参数。为了避免意料之外的结果,必须限定参数的上限和下限,否则就容易误传入非正确的int值,编译器是检查不出这类错误的,全靠人为控制。另一方面,使用静态常量时候,常常不够直观,不看定义,谁也不知道1、0、-1究竟表示什么,而且当有要罗列多少种方向的需求的时候,也不方便。
2、如果存在int值相同的常量,很有可能产生混淆。看下面代码:
这时如果传入的是Role.MANAGER,也是一样的。
因此这样的在枚举出现以后,这样的定义并不提倡。
以下是枚举的定义。
再来这段代码,出错的概率就小很多,代码也清晰很多。
二、枚举的实现原理。
正如前面所说,枚举是一种特殊的类。使用enmu关键字定义枚举,编译后会生成一个相关类,继承自java.lang.Enum,也就是说,在Java中,关键字enum实际上是一个语法糖(Android的AIDL貌似一回事),enum经过编译器,变成一个继承自java.lang.Enum的类。查看EnumSex编译后的EnumSex.class
不太看的懂,大概就是编译器为我们生产了EnumSex类,定义了MALE,FEMALE,LADY_BOY三个静态整型常量,static{}静态初始化实例,value和valueof两个静态方法。
三、枚举的常见用法。
既然继承自Enum类,先看看Enum类。
这是一个抽象类,实现了Comparable和Serializalble接口。这在后面单例模式应用中很关键。
常见方法:
这里主要说明一下
编译器生成的value()和valueof()方法
Enum类没有value()方法,方法value是编译器生成的static方法,用于返回所有枚举值。
方法Enum.valueof()有两个参数,编译器生成的valueof()只有一个参数,实际上调用的还是Enum.valueof, 只是编译器简化了一下,返回对应的枚举值。
上述我们提到当枚举实例向上转型为Enum类型后,values()方法将会失效,也就无法一次性获取所有枚举实例变量,但是由于Class对象的存在,即使不使用values()方法,还是有可能一次获取到所有枚举实例变量的,在Class对象中存在如下方法:
因此通过getEnumConstants()方法,同样可以轻而易举地获取所有枚举实例变量下面通过代码来演示这个功能:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
正如上述代码所展示,通过Enum的class对象的getEnumConstants方法,我们仍能一次性获取所有的枚举实例常量.
部分摘转自:http://blog.csdn.net/javazejian/article/details/71333103
一、Java枚举(enum)的定义。
Java5之前,没有枚举,定义常量的常见方式是这样的:
/** * Created by gyx on 2017/11/29. * 没有枚举时,常见的常量定义方式 */ public class Sex { public final static int MALE = 1;//男性 public final static int FEMALE = 0;//女性 public final static int LADY_BOY = -1;//人妖 }
这种定义方式没错,但是存在以下几点不足:
1、存在类型安全隐患。看下面代码:
public void setSex(int sex) { this.sex = sex; }
方法的参数是int型,即任何的int类型的值不限1、0、-1都能够作为该方法的参数。为了避免意料之外的结果,必须限定参数的上限和下限,否则就容易误传入非正确的int值,编译器是检查不出这类错误的,全靠人为控制。另一方面,使用静态常量时候,常常不够直观,不看定义,谁也不知道1、0、-1究竟表示什么,而且当有要罗列多少种方向的需求的时候,也不方便。
2、如果存在int值相同的常量,很有可能产生混淆。看下面代码:
public class Role { public final static int MANAGER = 1; }
/** * 入门登记 * @param sex */ private void bookIn(int sex){ if(sex == Sex.MALE){ System.out.println("男"); } }
这时如果传入的是Role.MANAGER,也是一样的。
因此这样的在枚举出现以后,这样的定义并不提倡。
以下是枚举的定义。
public enum EnumSex { MALE,FEMALE,LADY_BOY }
再来这段代码,出错的概率就小很多,代码也清晰很多。
private void bookIn(EnumSex sex){ if(sex == EnumSex.MALE){ System.out.println("男"); } }
二、枚举的实现原理。
正如前面所说,枚举是一种特殊的类。使用enmu关键字定义枚举,编译后会生成一个相关类,继承自java.lang.Enum,也就是说,在Java中,关键字enum实际上是一个语法糖(Android的AIDL貌似一回事),enum经过编译器,变成一个继承自java.lang.Enum的类。查看EnumSex编译后的EnumSex.class
public final class EnumSex extends java.lang.Enum<EnumSex> { public static final EnumSex MALE; descriptor: LEnumSex; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM public static final EnumSex FEMALE; descriptor: LEnumSex; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM public static final EnumSex LADY_BOY; descriptor: LEnumSex; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM public static EnumSex[] values(); descriptor: ()[LEnumSex; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #1 // Field $VALUES:[LEnumSex; 3: invokevirtual #2 // Method "[LEnumSex;".clone:()Ljava/lang/Object; 6: checkcast #3 // class "[LEnumSex;" 9: areturn LineNumberTable: line 4: 0 public static EnumSex valueOf(java.lang.String); descriptor: fb4c (Ljava/lang/String;)LEnumSex; flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: ldc #4 // class EnumSex 2: aload_0 3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljav a/lang/Enum; 6: checkcast #4 // class EnumSex 9: areturn LineNumberTable: line 4: 0 LocalVariableTable: Start Length Slot Name Signature 0 10 0 name Ljava/lang/String; static {}; descriptor: ()V flags: ACC_STATIC Code: stack=4, locals=0, args_size=0 0: new #4 // class EnumSex 3: dup 4: ldc #7 // String MALE 6: iconst_0 7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #9 // Field MALE:LEnumSex; 13: new #4 // class EnumSex 16: dup 17: ldc #10 // String FEMALE 19: iconst_1 20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 23: putstatic #11 // Field FEMALE:LEnumSex; 26: new #4 // class EnumSex 29: dup 30: ldc #12 // String LADY_BOY 32: iconst_2 33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 36: putstatic #13 // Field LADY_BOY:LEnumSex; 39: iconst_3 40: anewarray #4 // class EnumSex 43: dup 44: iconst_0 45: getstatic #9 // Field MALE:LEnumSex; 48: aastore 49: dup 50: iconst_1 51: getstatic #11 // Field FEMALE:LEnumSex; 54: aastore 55: dup 56: iconst_2 57: getstatic #13 // Field LADY_BOY:LEnumSex; 60: aastore 61: putstatic #1 // Field $VALUES:[LEnumSex; 64: return LineNumberTable: line 5: 0 line 4: 39 }
不太看的懂,大概就是编译器为我们生产了EnumSex类,定义了MALE,FEMALE,LADY_BOY三个静态整型常量,static{}静态初始化实例,value和valueof两个静态方法。
三、枚举的常见用法。
既然继承自Enum类,先看看Enum类。
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable
这是一个抽象类,实现了Comparable和Serializalble接口。这在后面单例模式应用中很关键。
常见方法:
返回类型 | 方法名称 | 方法说明 |
---|---|---|
int | compareTo(E o) | 比较此枚举与指定对象的顺序 |
boolean | equals(Object other) | 当指定对象等于此枚举常量时,返回 true。 |
Class<?> | getDeclaringClass() | 返回与此枚举常量的枚举类型相对应的 Class 对象 |
String | name() | 返回此枚举常量的名称,在其枚举声明中对其进行声明 |
int | ordinal() | 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零) |
String | toString() | 返回枚举常量的名称,它包含在声明中 |
static<T extends Enum<T>> T | static valueOf(Class<T> enumType, String name) | 返回带指定名称的指定枚举类型的枚举常量。 |
ordinal()方法,该方法获取的是枚举变量在枚举类中声明的顺序,下标从0开始,如日期中的MONDAY在第一个位置,那么MONDAY的ordinal值就是0,如果MONDAY的声明位置发生变化,那么ordinal方法获取到的值也随之变化,注意在大多数情况下我们都不应该首先使用该方法,毕竟它总是变幻莫测的。
compareTo(E o)方法则是比较枚举的大小,注意其内部实现是根据每个枚举的ordinal值大小进行比较的。
name()方法与
toString()几乎是等同的,都是输出变量的字符串形式。至于
valueOf(Class<T> enumType, String name)方法则是根据枚举类的Class对象和枚举名称获取枚举常量,注意该方法是静态的,后面在枚举单例时,我们还会详细分析该方法。
编译器生成的value()和valueof()方法
Enum类没有value()方法,方法value是编译器生成的static方法,用于返回所有枚举值。
方法Enum.valueof()有两个参数,编译器生成的valueof()只有一个参数,实际上调用的还是Enum.valueof, 只是编译器简化了一下,返回对应的枚举值。
枚举与Class对象
上述我们提到当枚举实例向上转型为Enum类型后,values()方法将会失效,也就无法一次性获取所有枚举实例变量,但是由于Class对象的存在,即使不使用values()方法,还是有可能一次获取到所有枚举实例变量的,在Class对象中存在如下方法:返回类型 | 方法名称 | 方法说明 |
---|---|---|
T[] | getEnumConstants() | 返回该枚举类型的所有元素,如果Class对象不是枚举类型,则返回null。 |
boolean | isEnum() | 当且仅当该类声明为源代码中的枚举时返回 true |
//正常使用 Day[] ds=Day.values(); //向上转型Enum Enum e = Day.MONDAY; //无法调用,没有此方法 //e.values(); //获取class对象引用 Class<?> clasz = e.getDeclaringClass(); if(clasz.isEnum()) { Day[] dsz = (Day[]) clasz.getEnumConstants(); System.out.println("dsz:"+Arrays.toString(dsz)); } /** 输出结果: dsz:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY] */1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
正如上述代码所展示,通过Enum的class对象的getEnumConstants方法,我们仍能一次性获取所有的枚举实例常量.
部分摘转自:http://blog.csdn.net/javazejian/article/details/71333103
相关文章推荐
- java枚举
- 《Thinking in Java》学习笔记——第三章:控制程序流程
- Java 数据类型在实际开发中应用二枚举
- Java枚举的七种常见用法
- 枚举系列 求N!所产生的数后面有多少个0 java版
- java枚举使用详解
- java enum枚举的使用
- Java 利用枚举实现单例模式
- Java枚举的七种常见用法
- java 基础总结 -- enum 枚举的基础使用
- java 枚举
- Java 枚举(enum) 详解7种常见的用法
- java中不太常见的东西(1) - 枚举enum
- 浅谈在Java开发中的枚举的作用和用法
- JAVA枚举的作用与好处
- Java 的枚举(Enums) 可以实现接口(Interfaces)
- Freemarker调用java静态方法(也可以调用常量,枚举)
- 学习笔记-- java中使用SQL语言
- 黑马程序员--java高新技术 25--枚举,反射
- Java基础之枚举妙用