Bootstrap

Enum枚举类与静态变量和静态数组的区别

组成结构

先来看下Enum枚举类,静态变量,静态数组的初始化过程,以下面为例子:

public enum FruitEnum {

    APPLE, ORANGE, BANANA, PEAR, CANTALOUPE, CHERRY, KIWIFRUIT, WATERMELON;

    static String value = "i";
    
    static String[] strings = {"a", "b", "c", "d", "e", "f", "g", "h"};

}

Enum枚举类

	/**
	* 每一个枚举值都分在一个enum
	**/
	// access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; APPLE
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; ORANGE
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; BANANA
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; PEAR
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; CANTALOUPE
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; CHERRY
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; KIWIFRUIT
	
	 // access flags 0x4019
	 public final static enum Lcn/abs/FruitEnum; WATERMELON

	/**
	*	一个枚举值初始化一个枚举类对象
	*	ICONST_* 代表的是枚举序列号
	**/
	NEW cn/abs/FruitEnum
	DUP
	LDC "APPLE"
	ICONST_0
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.APPLE : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "ORANGE"
	ICONST_1
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.ORANGE : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "BANANA"
	ICONST_2
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.BANANA : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "PEAR"
	ICONST_3
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.PEAR : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "CANTALOUPE"
	ICONST_4
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.CANTALOUPE : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "CHERRY"
	ICONST_5
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.CHERRY : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "KIWIFRUIT"
	BIPUSH 6
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.KIWIFRUIT : Lcn/abs/FruitEnum;
	NEW cn/abs/FruitEnum
	DUP
	LDC "WATERMELON"
	BIPUSH 7
	INVOKESPECIAL cn/abs/FruitEnum.<init> (Ljava/lang/String;I)V
	PUTSTATIC cn/abs/FruitEnum.WATERMELON : Lcn/abs/FruitEnum;
	
	/**
	*	提取每一个枚举类对象,并封装成一个枚举静态数组 cn/abs/FruitEnum.$VALUES
	*	ICONST_* 代表数组序列号
	**/
	BIPUSH 8
	ANEWARRAY cn/abs/FruitEnum
	DUP
	ICONST_0
	GETSTATIC cn/abs/FruitEnum.APPLE : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	ICONST_1
	GETSTATIC cn/abs/FruitEnum.ORANGE : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	ICONST_2
	GETSTATIC cn/abs/FruitEnum.BANANA : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	ICONST_3
	GETSTATIC cn/abs/FruitEnum.PEAR : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	ICONST_4
	GETSTATIC cn/abs/FruitEnum.CANTALOUPE : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	ICONST_5
	GETSTATIC cn/abs/FruitEnum.CHERRY : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	BIPUSH 6
	GETSTATIC cn/abs/FruitEnum.KIWIFRUIT : Lcn/abs/FruitEnum;
	AASTORE
	DUP
	BIPUSH 7
	GETSTATIC cn/abs/FruitEnum.WATERMELON : Lcn/abs/FruitEnum;
	AASTORE
	PUTSTATIC cn/abs/FruitEnum.$VALUES : [Lcn/abs/FruitEnum;

可以看出Enum枚举类会将每一个枚举值都包装成一个带有枚举序列号的枚举类对象,然后再将枚举类对象封装成一个枚举数组。

另外,如上图所示(例如:public final static enum Lcn/abs/FruitEnum; APPLE)enum 用了 final 来修饰,Enum枚举类是不能够修改值。

静态变量

    LDC "i"
    PUTSTATIC cn/abs/FruitEnum.value : Ljava/lang/String;

从上面可以发现静态变量等同于一个枚举值初始化一个枚举类对象的环节。

静态数组

ANEWARRAY java/lang/String
    DUP
    ICONST_0
    LDC "a"
    AASTORE
    DUP
    ICONST_1
    LDC "b"
    AASTORE
    DUP
    ICONST_2
    LDC "c"
    AASTORE
    DUP
    ICONST_3
    LDC "d"
    AASTORE
    DUP
    ICONST_4
    LDC "e"
    AASTORE
    DUP
    ICONST_5
    LDC "f"
    AASTORE
    DUP
    BIPUSH 6
    LDC "g"
    AASTORE
    DUP
    BIPUSH 7
    LDC "h"
    AASTORE
    PUTSTATIC cn/abs/FruitEnum.strings : [Ljava/lang/String;

由此可见静态数组等同于把每一个枚举类对象封装成一个枚举数组的环节。

组成结构的区别

相同之处

  1. Enum枚举类在中间把一个枚举值包装成一个枚举类对象,这跟静态变量是一样的操作和结构。
  2. Enum枚举类最后也是封装成了一个静态数组,这是跟静态数组一样的最终结构形态。

不同之处

  1. Enum枚举类会把每一个枚举值都包装成一个枚举类对象后再封装成一个静态数组,而不是像静态数组把每一个数值都直接封装到一个静态数组中。
  2. Enum枚举类比静态变量多了对静态数组的封装。

用法使用

相同之处

  1. Enum枚举类,静态变量和静态数组都是一经定义不可变更。
  2. Enum枚举类,静态变量和静态数组都是存放在Metaspace中。

不同之处

  1. Enum枚举类具有枚举序列号,可以通过枚举类对象方法ordinal()提取,能够利用此枚举序列号进行枚举类对象的序列比较和排序,而静态数组可以按照stream流方式进行操作。
  2. Enum枚举类都是通过<Enum Clazz>.<Enum Value>来获取枚举值,使用上安全,不会出现越界,而静态数组需要通过指定index来获取数值,在指定index的时候不能保证index不越界,index越界会抛出错误异常,例如:ArrayIndexOutOfBoundsException,IndexOutOfBoundsException。
  3. 静态数组可以通过index直接获取值,Enum枚举类则是通过直观的名字获取值。
  4. Enum枚举可以在switch()中运用,静态变量和静态数组不能代表类型又代表不同数值没有办法在switch()中使用。
  5. Enum枚举类的枚举值就是枚举对象的名字,元素类型单一,并且需要匹配对象名字的命名规范。而静态变量和静态数组可以应用于不同的元素类型,包括基本类型和对象类型。
;