前言:
眼前看官们对“枚举怎么用java”大约比较注意,同学们都需要学习一些“枚举怎么用java”的相关内容。那么小编同时在网络上收集了一些有关“枚举怎么用java””的相关知识,希望看官们能喜欢,我们一起来学习一下吧!枚举的定义
public enum Color { Red,Blue,Green;}## 枚举的使用Color red = Color.Red;//枚举的其中一个类型Color[] values = Color.values();//获取所有的枚举类型String name = red.name();//可以获得枚举值的名称int ordinal = red.ordinal();//可以获得枚举值的编号原理
那我们定义枚举类型后,到底发生了什么呢?我们对枚举的实现原理进行探究。
我们来解析下Color.class文件,命令javap Color
public final class Color extends java.lang.Enum<Color> { public static final Color Red; public static final Color Blue; public static final Color Green; public static final Color[] $VALUES; public static Color[] values(); public static Color valueOf(java.lang.String); static {};}
从解析后的文件中我们可以知道
1.枚举类是final 的,不能被继承
2.枚举类在经过编译后生成一个继承java.lang.Enum 的类 Color
3.编译后的枚举值,是该类的Color类型的成员变量,如 Red、Bule、Green ,并且是final static 修饰
4.枚举编译后的类添加了静态的values() 和valueOf(java.lang.String) 方法
5.静态代码块static {}
进一步细化Color.class
命令javap -c Color
public final class Color extends java.lang.Enum<Color> { public static final Color Red; public static final Color Blue; public static final Color Green; public static Color[] values(); Code: 0: getstatic #1 // Field $VALUES:[LColor; 3: invokevirtual #2 // Method "[LColor;".clone:()Ljava/lang/Object; 6: checkcast #3 // class "[LColor;" 9: areturn public static Color valueOf(java.lang.String); Code: 0: ldc #4 // class Color 2: aload_0 3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; 6: checkcast #4 // class Color 9: areturn static {}; Code: 0: new #4 // class Color 3: dup 4: ldc #7 // String Red 6: iconst_0 7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 10: putstatic #9 // Field Red:LColor; 13: new #4 // class Color 16: dup 17: ldc #10 // String Blue 19: iconst_1 20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 23: putstatic #11 // Field Blue:LColor; 26: new #4 // class Color 29: dup 30: ldc #12 // String Green 32: iconst_2 33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V 36: putstatic #13 // Field Green:LColor; 39: iconst_3 40: anewarray #4 // class Color 43: dup 44: iconst_0 45: getstatic #9 // Field Red:LColor; 48: aastore 49: dup 50: iconst_1 51: getstatic #11 // Field Blue:LColor; 54: aastore 55: dup 56: iconst_2 57: getstatic #13 // Field Green:LColor; 60: aastore 61: putstatic #1 // Field $VALUES:[LColor; 64: return}
还原后的代码如下:
public final class Color extends java.lang.Enum<Color> { //定义的枚举成员 public static final Color Red; public static final Color Blue; public static final Color Green; //编译器自动生成的 javap -c 还查不出来,疑惑 public static final /* synthetic */ Color[] $VALUES;//编译器自动生成的 public static Color[] values(){ /** * 0: getstatic #1 // Field $VALUES:[LColor; * 3: invokevirtual #2 // Method "[LColor;".clone:()Ljava/lang/Object; * 6: checkcast #3 // class "[LColor;" * 9: areturn */ return $VALUES.clone(); } public static Color valueOf(java.lang.String s){ /** * 0: ldc #4 // class Color * 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 Color * 9: areturn */ return Enum.valueOf(Color.class,s); } protected Color(String name, int ordinal) { super(name, ordinal); } static { /** * 0: new #4 // class Color * 3: dup * 4: ldc #7 // String Red * 6: iconst_0 * 7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V * 10: putstatic #9 // Field Red:LColor; */ Red=new Color("Red",0); /** * 13: new #4 // class Color * 16: dup * 17: ldc #10 // String Blue * 19: iconst_1 * 20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V * 23: putstatic #11 // Field Blue:LColor; */ Blue=new Color("Blue",1); /** * 26: new #4 // class Color * 29: dup * 30: ldc #12 // String Green * 32: iconst_2 * 33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V * 36: putstatic #13 // Field Green:LColor; */ Green=new Color("Green",2); /** * 39: iconst_3 * 40: anewarray #4 // class Color * 43: dup * 44: iconst_0 * 45: getstatic #9 // Field Red:LColor; * 48: aastore * 49: dup * 50: iconst_1 * 51: getstatic #11 // Field Blue:LColor; * 54: aastore * 55: dup * 56: iconst_2 * 57: getstatic #13 // Field Green:LColor; * 60: aastore * 61: putstatic #1 // Field $VALUES:[LColor; */ $VALUES=new Color[]{Red,Blue,Green}; };}
通过上面还原后的代码可知,该类的static代码块 中编译器帮我们生成枚举中的每个成员,实际上就是生成对象并赋值给静态变量。
枚举的扩展单例模式
枚举其实就是编译帮我们在静态代码块中创建一个或多个枚举成员对象,如果我们只定义一个枚举成员,这样就是一个单例对象
public enum Singleton { INSTANCE; public void doSometing(){ System.out.println("doing"); }}
代码如此简单,不仅如此,这样的方式还可以解决 反射攻击 和 反序列化 导致的单例失败的问题。
避免反射攻击
在获取实例时进行了枚举判断,如果是枚举类型的则直接抛出异常。
Jdk1.8Class.clss 文件的416..417 行
public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ .... if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); ..... return inst; }反序列化
枚举的序列时仅将枚举对象的name属性输出到结果中,在反序列化时则是通过java.lang.Enum 的 valueOf 方法是根据名字在jvm中查找对象的。
同时编译器还禁止对枚举的定制化序列机制,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。
策略模式
一种行为,多种结果,不同结果的实现,名曰策略。
public enum Calculator { //加法运算 ADD("+"){ public int exec(int a,int b){ return a+b; } }, //减法运算 SUB("-"){ public int exec(int a,int b){ return a - b; } }; String value = ""; //定义成员值类型 Calculator(String _value){ this.value = _value; } //获得枚举成员的值 public String getValue(){ return this.value; } //声明一个抽象函数 public abstract int exec(int a,int b);}总结枚举其实就是编写代码方面的语法糖,仍然是一个完整的类,暴露了几个静态变量,隐藏掉了大部分细节枚举的成员变量是在编译后的静态代码块逐个创建实例来实现的枚举的values()和valueOf()方法都是编译器帮我们创建出来的在调用values()方法时,返回的对象是克隆出来的一份新的,修改对原对象没有影响枚举可以实现单例模式,能避免反射攻击和反序列化问题避免反射攻击是因为枚举类不允许通过反射实例化反序列化是通过Enum.valueOf到jvm中根据class,name去查找的枚举可以实现策略模式,优化代码,避免大量的if...else的出现
标签: #枚举怎么用java #javaenum值 #java枚举的定义 #java 枚举的使用 #javaint枚举