枚举类型是指有一组固定的常量组成合法值的类型。 --Effective Java 第二版
有时恰恰因为它,你才能够“优雅而干净”地解决问题。 --Java编程思想 第四版
枚举使用场景
-
常量
-
switch
-
添加方法
-
实现接口
-
使用接口组织枚举
枚举替代常量的优势
在Effective Java和编写高质量代码两本书种都“推荐使用枚举定义常量”
1.枚举常量更简单
2.枚举常量属于稳态
3.枚举具有内置方法
4.枚举可以自定义方法
枚举基础
方法
public static T[] values()
public static T valueOf(String name)
public static T valueOf(Class<T> enumType,String name)
public final int ordinal()
public final String name()
样例源码反编译
代码
public enum SeasonJavap
{
SPRING ,
SUMMER ,
AUTUMN ,
WINTER ;
}
反编译
public final class com.somin.枚举.SeasonJavap extends java.lang.Enum<com.somin.枚举.SeasonJavap> {
public static final com.somin.枚举.SeasonJavap SPRING;
public static final com.somin.枚举.SeasonJavap SUMMER;
public static final com.somin.枚举.SeasonJavap AUTUMN;
public static final com.somin.枚举.SeasonJavap WINTER;
public static com.somin.枚举.SeasonJavap[] values();
Code:
0: getstatic #1 // Field $VALUES:[Lcom/somin/枚举/SeasonJavap;
3: invokevirtual #2 // Method "[Lcom/somin/枚举/SeasonJavap;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lcom/somin/枚举/SeasonJavap;"
9: areturn
public static com.somin.枚举.SeasonJavap valueOf(java.lang.String);
Code:
0: ldc #4 // class com/somin/枚举/SeasonJavap
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class com/somin/枚举/SeasonJavap
9: areturn
static {};
Code:
0: new #4 // class com/somin/枚举/SeasonJavap
3: dup
4: ldc #7 // String SPRING
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field SPRING:Lcom/somin/枚举/SeasonJavap;
13: new #4 // class com/somin/枚举/SeasonJavap
16: dup
17: ldc #10 // String SUMMER
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field SUMMER:Lcom/somin/枚举/SeasonJavap;
26: new #4 // class com/somin/枚举/SeasonJavap
29: dup
30: ldc #12 // String AUTUMN
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field AUTUMN:Lcom/somin/枚举/SeasonJavap;
39: new #4 // class com/somin/枚举/SeasonJavap
42: dup
43: ldc #14 // String WINTER
45: iconst_3
46: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
49: putstatic #15 // Field WINTER:Lcom/somin/枚举/SeasonJavap;
52: iconst_4
53: anewarray #4 // class com/somin/枚举/SeasonJavap
56: dup
57: iconst_0
58: getstatic #9 // Field SPRING:Lcom/somin/枚举/SeasonJavap;
61: aastore
62: dup
63: iconst_1
64: getstatic #11 // Field SUMMER:Lcom/somin/枚举/SeasonJavap;
67: aastore
68: dup
69: iconst_2
70: getstatic #13 // Field AUTUMN:Lcom/somin/枚举/SeasonJavap;
73: aastore
74: dup
75: iconst_3
76: getstatic #15 // Field WINTER:Lcom/somin/枚举/SeasonJavap;
79: aastore
80: putstatic #1 // Field $VALUES:[Lcom/somin/枚举/SeasonJavap;
83: return
}
反编译后结论
(当一个Java类,第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的)
- 枚举的本质是一个类
- 枚举类继承于Enum类
- 创建一个enum类型是线程安全的。
Enum源码
属性
private final String name;
private final int ordinal;
方法
public final String name()
public final int ordinal()
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
public String toString()//返回name
public final boolean equals(Object other)
public final int hashCode()
protected final Object clone()//不支持拷贝直接抛异常
protected final void finalize()
//不支持序列化
private void readObject(ObjectInputStream in)
private void readObjectNoData()
values(),valueOf(String name)是如何产生的?
我看了网上很多说法,但是多数给出的结论都不清不楚,有更多的还是解释错误。经过查找资料得到了权威结果,大家看一下,参考下面文章
https://blog.csdn.net/smd2575624555/article/details/113363688
反射和枚举
我们能不能通过反射去进行实例化这个枚举类 ?
不能被实例化,单例可以被反射破坏,使用枚举创建单例
反射枚举方法
特定方法
public boolean isEnum()
public T[] getEnumConstants()
通用方法演示
public Constructor<?>[] getDeclaredConstructors()
public Method[] getDeclaredMethods()
public Field[] getDeclaredFields()
public T newInstance()
枚举进阶
方法添加
普通方法添加
- 构造方法自定义声明
- 注意修饰符范围
- 可以选择是否进行继承方法
抽象方法添加
- 方法是用abstract修饰
- 枚举类型必须继承方法
- 查看编译后的.class有什么变化
工厂方法模式(Factory Method Pattern)是“创建对象的接口,让子类决定实
例化哪一个类,并使一个类的实例化延迟到其子类”。
使用接口组织枚举
- 所有的 enum 都继承自 Java.lang.Enum 类,也可以实现其他接口
- 再接口中实现枚举,再利用向上转型
- 不推荐,让代码更复杂了
EnumSet
优点:非常快速高效,具有更好的表达能力
声明方式使用隐式创建
继承和实现
extends AbstractSet implements Cloneable, java.io.Serializable
实现方式是位向量,实现类时RegularEnumSet和JumboEnumSet为基础,已下是生成EnumSet核心源码
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
属性
final Class<E> elementType;
final Enum<?>[] universe;
方法
EnumSet.allOf(SeasonDomeType.class);
EnumSet.complementOf(set1);
EnumSet.copyOf(EnumSet);
EnumSet.noneOf(SeasonDomeType.class);
EnumSet.of(SeasonDomeType.SPRING);
EnumSet.range(SeasonDomeType.SPRING,SeasonDomeType.AUTUMN);
EnumMap
优点:不但效率最高,而且没有额外的空间浪费
内部以一个非常紧凑的数组存储value,并且根据enum类型的key直接定位到内部数组的索引
和map操作基本相同,主要差异
在操作put时,会检查一下枚举类型
public V put(K key, V value)->private void typeCheck(K key)
在操作get时,会检查一下枚举类型是否有效
public V get(Object key)->private boolean isValidKey(Object key)