java中的枚举类型解析
来源:互联网 发布:中国联通3g网络制式 编辑:程序博客网 时间:2024/04/28 15:12
背景
学过c/c++的同学都知道,c/c++里面的枚举变量在编译的时候,都会用相应的值替换掉枚举常量。
java里面也有枚举类型,那么java里面的枚举是否和c/c++里面的枚举类型一样呢?
分析过程
为了分析java里面的枚举类型,最好的方法也就是反汇编的class文件,来分析java的枚举类型到底是个什么东西。
将下面列子编译为class文件
public class Main { enum Ops { ADD, SUB } public static void main(String[] args) { System.out.println(Ops.ADD.name()); }}
在bin下面发现有两个class文件:Main.class
和Main$Ops.class
文件,可以知道枚举类型Ops编译之后也是一个类。
反编译Main$Ops.class,查看它的指令,可以看到下面内容:
chous-MacBook-Pro:TestJava chaohuang$ javap -c -p Main\$Ops.class Compiled from "Main.java"final class com.kevin.TestJava.Main$Ops extends java.lang.Enum<com.kevin.TestJava.Main$Ops> { public static final com.kevin.TestJava.Main$Ops ADD; public static final com.kevin.TestJava.Main$Ops SUB; private static final com.kevin.TestJava.Main$Ops[] ENUM$VALUES; static {}; Code: // 省略 private com.kevin.TestJava.Main$Ops(java.lang.String, int); Code: // 省略 public static com.kevin.TestJava.Main$Ops[] values(); Code: // 省略 public static com.kevin.TestJava.Main$Ops valueOf(java.lang.String); Code: // 省略 }
可以看到Ops类是继承于java.lang.Enum
,而且有两个成员变量:ADD
和SUB
(这正是Ops里面定义的两个枚举值)。并且有三个成员方法,先分别分析下这三个方法的作用。
private com.kevin.TestJava.Main$Ops(java.lang.String, int); Code: 0: aload_0 // 将#0局部变量压到栈上 1: aload_1 // 将#1局部变量压到栈上 2: iload_2 // 将#2局部变量压到栈上 3: invokespecial #27 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V 6: return
可以看到这个构造方法有两个参数,调用父类的构造方法(父类的构造见Enum定义)。
public static com.kevin.TestJava.Main$Ops[] values(); Code: 0: getstatic #23 // Field ENUM$VALUES:[Lcom/kevin/TestJava/Main$Ops; 将静态变量压到栈上 3: dup // 复制一份静态变量的引用压到栈上 4: astore_0 // 将栈顶元素(静态变量ENUM$VALUES)保存到#0局部变量中,并弹出栈顶元素 5: iconst_0 // 将常量0压到栈上 6: aload_0 // 将#0局部变量的内容压到栈上 7: arraylength // 计算当前栈顶变量的数组长度,弹出栈顶元素,压入数组长度 8: dup // 复制栈顶元素,压到栈顶 9: istore_1 // 将栈顶元素保存到#1局部变量 10: anewarray #1 // class com/kevin/TestJava/Main$Ops,新建一个长度为当前栈顶元素值的数组,弹出栈顶元素,将新创建的数组引用压到栈上 13: dup // 复制栈顶元素,压到栈顶 14: astore_2 // 将栈顶元素保存到#2局部变量,并弹出 15: iconst_0 // 将常量0压到栈上 16: iload_1 // 将#1局部变量的值压到栈上 17: invokestatic #31 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V,调用arraycopy方法 20: aload_2 // 将#2局部变量压到栈上 21: areturn
分析完这段汇编,可以发现values
方法的作用是将类的静态变量ENUM$VALUES
复制一份,然后返回给调用者。
public static com.kevin.TestJava.Main$Ops valueOf(java.lang.String); Code: 0: ldc #1 // class com/kevin/TestJava/Main$Ops,将class引用压到栈上 2: aload_0 // 将#0局部变量压到栈上(由于是静态方法,所以#0就是第一个参数) 3: invokestatic #39 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;,调用父类的valueOf方法 6: checkcast #1 // class com/kevin/TestJava/Main$Ops,检查下返回值的类型 9: areturn
由上面可知valueOf
的作用就是传入一个字符串,然后返回对应的枚举类型值。
static {}; Code: 0: new #1 // class com/kevin/TestJava/Main$Ops 3: dup 4: ldc #13 // String ADD 6: iconst_0 7: invokespecial #14 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #18 // Field ADD:Lcom/kevin/TestJava/Main$Ops; 13: new #1 // class com/kevin/TestJava/Main$Ops 16: dup 17: ldc #20 // String SUB 19: iconst_1 20: invokespecial #14 // Method "<init>":(Ljava/lang/String;I)V 23: putstatic #21 // Field SUB:Lcom/kevin/TestJava/Main$Ops; 26: iconst_2 27: anewarray #1 // class com/kevin/TestJava/Main$Ops 30: dup 31: iconst_0 32: getstatic #18 // Field ADD:Lcom/kevin/TestJava/Main$Ops; 35: aastore 36: dup 37: iconst_1 38: getstatic #21 // Field SUB:Lcom/kevin/TestJava/Main$Ops; 41: aastore 42: putstatic #23 // Field ENUM$VALUES:[Lcom/kevin/TestJava/Main$Ops; 45: return
这段静态代码块好理解,分别给静态变量ADD
和SUB
构建类对象,并且创建一个数组,将两个对象的引用保存到数组中。
总结
经过分析可以发现:
- 枚举类型是一个类,继承java.lang.Enum
- 枚举类型中的每个值都是类对象,并且是枚举类型的静态成员
- 枚举类型中有个数组类型的静态成员,保存了所有的枚举值,并且可以通过成员方法values获取一个复制的数组
- 可以通过枚举值对应的字符串获取对应的枚举对象
0 0
- java中的枚举类型解析
- Java中的枚举类型
- Java中的枚举类型
- Java中的枚举类型
- java中的枚举类型
- java中的枚举类型
- Java中的枚举类型
- java中的枚举类型
- java中的枚举类型
- JAVA中的枚举类型
- JAVA中的枚举类型
- JAVA中的枚举类型
- java中的枚举类型
- JAVA中的枚举类型
- Java中的枚举类型
- Java中的枚举类型
- java中的枚举----类型安全的枚举
- 感受一下Java中的“枚举类型”
- 将ACCESS数据库数据转到SQL server数据库中(通用)
- 谈摄影测量与遥感专业的学习
- 怎么更改MyEclipse中文件的名字
- 【译】基础篇:RCU是什么?
- 黑马程序员---Java基础---Object类和String类
- java中的枚举类型解析
- DOS命令
- Android性能优化之布局优化篇
- 虚幻引擎4的基于物理模型光照
- 如何反编译.class文件及阅读java指令
- oracle之字符链接 concat(String,String)
- linux基本知识点
- 博客迁移到 http://www.cnblogs.com/linuxbug
- linux进程监控与自动重启实现