java基础 -- 枚举使用与源码解析

枚举类型是指有一组固定的常量组成合法值的类型。 --Effective Java 第二版
有时恰恰因为它,你才能够“优雅而干净”地解决问题。 --Java编程思想 第四版

枚举使用场景

  1. 常量

  2. switch

  3. 添加方法

  4. 实现接口

  5. 使用接口组织枚举

枚举替代常量的优势

在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类的加载和初始化过程都是线程安全的)

  1. 枚举的本质是一个类
  2. 枚举类继承于Enum类
  3. 创建一个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()

枚举进阶

方法添加

普通方法添加
  1. 构造方法自定义声明
  2. 注意修饰符范围
  3. 可以选择是否进行继承方法
抽象方法添加
  1. 方法是用abstract修饰
  2. 枚举类型必须继承方法
  3. 查看编译后的.class有什么变化

工厂方法模式(Factory Method Pattern)是“创建对象的接口,让子类决定实
例化哪一个类,并使一个类的实例化延迟到其子类”。

使用接口组织枚举
  1. 所有的 enum 都继承自 Java.lang.Enum 类,也可以实现其他接口
  2. 再接口中实现枚举,再利用向上转型
  3. 不推荐,让代码更复杂了

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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值