Java中的枚举类型(Enum)

Java中的枚举类型(Enum)

1 枚举类型初探

枚举类型,其语法总让人觉着怪怪的,如下:

import java.util.EnumSet;

public enum CarType {
	SportCarType, JeepCarType, HatchbackCarType
	/*
	 * Java自动给按照枚举值出现的顺序,从0开始分配了编号。
	 *  通过name()可以获得枚举值的名称,通过ordinal()可以获得枚举值的编号。
	 */
}

这里注意如果只有SportCarType, JeepCarType, HatchbackCarType,后面没有代码可以在最后一个HatchbackCarType后不加;但是如果还有内容需要加上。

简单的一行,就定义了包含三个值的枚举类型,缺总让人觉着语法有点怪异。而在使用时:

import org.junit.Test;

public class CarTest {
	@Test
	public void test() {
		System.out.println("SportCarType name:"+CarType.SportCarType.name());
		System.out.println("SportCarType ordinal:"+CarType.SportCarType.ordinal());
		
		System.out.println("JeepCarType name:"+CarType.JeepCarType.name());
		System.out.println("JeepCarType ordinal:"+CarType.JeepCarType.ordinal());
		
		System.out.println("HatchbackCarType name:"+CarType.HatchbackCarType.name());
		System.out.println("HatchbackCarType ordinal:"+CarType.HatchbackCarType.ordinal());
	
	}
}

就可以得到输出:

image-20220414152942570

2 枚举产生之前

如果不使用枚举,我们要对车的类型这三个值分别赋予一个数字,则常见的操作为:

public class CarType{
	public static final int SportCarType = 0;
	public static final int JeepCarType = 1;
	public static final int HatchbackCarType = 2;

}

上述方法定义十分繁琐,而且容易出错。例如我们定义的int数字出现重复,编译器也不会给出任何的警示。同时,这样的操作是实在太频繁了,最终Java 5中增加了枚举类型。

而是用枚举类型后,一切就变成了如下所示的简单几行:

public enum CarType {
    SportCarType, JeepCarType, HatchbackCarType
}

而且,Java自动给按照枚举值出现的顺序,从0开始分配了编号。通过name()可以获得枚举值的名称,通过ordinal()可以获得枚举值的编号。

3 枚举实现原理

那我们定义枚举类型后,到底发生了什么呢?我们对枚举的实现原理进行探究。

首先,我们在实现CarType枚举类时,并没有定义name()和ordinal()方法。我们从这里入手,点击该方法后,发现进入了一个抽象类:

public abstract class Enum<E extends Enum<E>>
    implements Comparable<E>, Serializable {}

并且,我们发现编译器不允许我们自行实现该抽象类从而构造一个新的类。但是,既然我们的CarType枚举类可以调用其中的方法,因此Season枚举类应该是继承了该抽象类。

为了验证这一猜想,我们让Season类继承一个其他的类,发现果然不可以,因为Java是不允许多继承的。

具体,我们对CarType类进行反编译

首先编译生成class文件

javac CarType.java

然后进行反编译

javap -c CarType.class

image-20220414153909765

Java程序的开发过程:首先编写一个Java的代码源文件后缀.java,该源文件经过Java的编译器javac编译成一个后缀为.class的字节码文件,再由解释器java解释成本地机器码来执行。
Java反编译:就是将生成的字节码文件(后缀.class)再还原为源文件(.java)。JDK提供的反编译器为javap,是一个.exe的可执行文件

Compiled from "CarType.java"
public final class CarType extends java.lang.Enum<CarType> {
  public static final CarType SportCarType;

  public static final CarType JeepCarType;

  public static final CarType HatchbackCarType;

  public static CarType[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[LCarType;
       3: invokevirtual #2                  // Method "[LCarType;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[LCarType;"
       9: areturn

  public static CarType valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class CarType
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class CarType
       9: areturn

  static {};
    Code:
       0: new           #4                  // class CarType
       3: dup
       4: ldc           #7                  // String SportCarType
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field SportCarType:LCarType;
      13: new           #4                  // class CarType
      16: dup
      17: ldc           #10                 // String JeepCarType
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field JeepCarType:LCarType;
      26: new           #4                  // class CarType
      29: dup
      30: ldc           #12                 // String HatchbackCarType
      32: iconst_2
      33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      36: putstatic     #13                 // Field HatchbackCarType:LCarType;
      39: iconst_3
      40: anewarray     #4                  // class CarType
      43: dup
      44: iconst_0
      45: getstatic     #9                  // Field SportCarType:LCarType;
      48: aastore
      49: dup
      50: iconst_1
      51: getstatic     #11                 // Field JeepCarType:LCarType;
      54: aastore
      55: dup
      56: iconst_2
      57: getstatic     #13                 // Field HatchbackCarType:LCarType;
      60: aastore
      61: putstatic     #1                  // Field $VALUES:[LCarType;
      64: return
}

我们看到,对与枚举类,有很多值的注意的点:

  • 枚举类在经过编译后确实是生成了一个扩展了java.lang.Enum的类
  • 枚举类是final的,因此我们无法再继承它了
  • 我们定义的每个枚举值都是该类中的一个成员,且成员的类型仍然是Season类型
  • 枚举类中被默认增加了许多静态方法,例如values()等

通过这里我们可以看到,在类的static操作中,编译器帮助我们生成每个枚举值的对象。

参考:

Java中的枚举类型(Enum)详解

https://blog.csdn.net/u011479200/article/details/80019827?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164992239516780264090251%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164992239516780264090251&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogtop_positive~default-1-80019827.nonecase&utm_term=java%E5%8F%8D%E7%BC%96%E8%AF%91&spm=1018.2226.3001.4450

posted @ 2022-05-16 20:46  记录学习Blog  阅读(676)  评论(0编辑  收藏  举报