Java枚举

一、背景

  1. 所属包java.lang包
  2. jdk1.5后引入的新特性

二、基本使用

(一)、 创建一个枚举

public enum TestEnum {
	A,B,C;
}

以上,创建了一个简单的枚举,这个枚举里有三个枚举项,分别是A,B,C。

需要注意的是:

  1. A,B,C每一个都称为枚举项,它们都是本类的实例。

  2. 在定义枚举项时,多个枚举项之间使用逗号分隔,最后一个枚举项后需要给出分号!但如果枚举类中只有枚举项(没有构造器、方法、实例变量),那么可以省略分号 。就像下面这样:

    public enum TestEnum {
    	A,B,C
    }
    

    但是如果有构造器、方法等枚举项必须在第一行,否则编译出错。

  3. 所有枚举类默认都是Enum(java.lang.Enum)类的子类,编译时默认会继承Enum类。无需手动使用extends关键字来继承。

(二)、给枚举赋值

枚举不能使用 = 赋值,而是使用构造方法赋值。

public enum TestEnum {
	A(1),B(2),C(3);
	
	private int value;
	
	private TestEnum(int value) {
		this.value = value;
	}
}

枚举可以有任意个属性,像这样:

public enum TestEnum {
	A(1, "a", true),B(2, "b", false),C(3, "c", false);
	
	private int intValue;
	private String stringValue;
	private boolean booleanValue;
	
	private TestEnum(int intValue, String stringValue, boolean booleanValue) {
		this.intValue = intValue;
		this.stringValue = stringValue;
		this.booleanValue = booleanValue;
	}
}

注意:

  1. 枚举的构造器只能使用private访问控制器,如果省略了其构造器的访问修饰符,则默认使用private修饰,如果强制指定访问控制符,则只能制定private。

  2. 由于枚举被设计成是单例模式,即枚举类型会由JVM在加载的时候,实例化枚举对象,所以你在枚举类中定义了多少个就会实例化多少个,JVM为了保证每一个枚举类元素的唯一实例,是不会允许外部进行new的,所以会把构造函数设计成private,防止用户生成实例,破坏唯一性。

(三)、实例化枚举对象

直接使用枚举类.枚举项的形式获取一个枚举对象:

public static void main(String[] args) {
	TestEnum enumC = TestEnum.C;
	System.out.println(enumC);
}
/* 输出 */
// C

注意:每个实例化的枚举对象都是单例的,通过以上方式获取到的枚举实例实际上是jvm在加载枚举的时候生成好的枚举对象。

(四)、获取枚举实例的值

在(二)的基础上,我们新增一个getValue()方法,用来获取当前枚举实例的值:

public enum TestEnum {
	A(1),B(2),C(3);
	
	private int value;
	
	private TestEnum(int value) {
		this.value = value;
	}
	
	public int getValue() {
		return value;
	}
}

使用如下方式获取枚举的值:

public static void main(String[] args) {
    TestEnum enumC = TestEnum.C;
	int value = enumC.getValue();
	System.out.println(value);
}
/* 输出 */
// 3

三、来自Enum的方法

(一)、getDeclaringClass

​ 返回与此枚举常量的枚举类型相对应的Class对象。 当且仅当e1.getDeclaringClass()== e2.getDeclaringClass()时,两个枚举常量e1和e2属于相同的枚举类型。(对于具有特定于常量的类主体的枚举常量,此方法返回的值可能不同于Object.getClass()方法返回的值。)

public static void main(String[] args) {
	TestEnum enumC = TestEnum.C;
	System.out.println(enumC.getDeclaringClass());;
}
/* 输出 */
// class com.test.TestEnum

(二)、valueOf

​ 返回具有指定名称的指定枚举类型的枚举常量。该名称必须与用于声明此类型的枚举常量的标识符完全匹配。(不允许使用多余的空格字符。)

public static void main(String[] args) {
    TestEnum enumC = TestEnum.C;
    System.out.println(enumC.valueOf("C"));
}
/* 输出 */
// C

(三)、name

​ 返回此枚举常量的名称,该名称与在其枚举声明中声明的完全相同。大多数程序员应该优先使用toString()方法,因为toString方法可能返回更用户友好的名称。此方法主要设计用于在特殊情况下正确性取决于获得确切名称的特殊情况,具体名称在发行版本之间不会有所不同。

public static void main(String[] args) {
    TestEnum enumC = TestEnum.C;
    System.out.println(enumC.name());
}
/* 输出 */
// C

(四)、ordinal

​ 返回此枚举常量的序数(其在枚举声明中的位置,其中初始常量的序数为零)。大多数程序员都不会使用这种方法。它设计用于复杂的基于枚举的数据结构,例如EnumSet和EnumMap。

public static void main(String[] args) {
    TestEnum enumC = TestEnum.C;
    System.out.println(enumC.ordinal());
}
/* 输出 */
// 2

(五)、values

​ 获取此枚举类定义的所有枚举常量,返回值是一个数组。

public static void main(String[] args) {
    TestEnum[] enums = TestEnum.values();
    for(TestEnum e:enums) {
        System.out.println("name:"+e.name()+"-->"+"ordinal:"+e.ordinal());
    }
}
/* 输出 */
// name:A-->ordinal:0
// name:B-->ordinal:1
// name:C-->ordinal:2

四、应用场景

  1. 实体类中需要定义的常量过多,将这些常量写成一个枚举,方便统一管理。

    现在有一个短信模板枚举如下:

public enum SmsTemplateEnum {
	REGISTER("register","注册"),
	FORGET("forget","忘记密码");
	
	private String code;
	private String title;

	private SmsTemplateEnum(String code, String title) {
		this.code = code;
		this.title = title;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
}

假设现在能获取到的数据只有短信的code属性,而实际需要的是title属性,这种情况下可以写一个根据code查找title的方法,实现代码如下:

// 根据短信的code属性获取title属性
public static String getTitleByCode(String code) {
    for (SmsTemplateEnum template : SmsTemplateEnum.values()) {
        if (template.getCode().equals(code)) {
            return template.getTitle();
        }
    }
    return null;
}
  1. switch语句

现在有一个季节枚举如下:

public enum Season {
	SPRING("春天"),
	SUMMER("夏天"),
	AUTUMN("秋天"),
	WINTER("冬天");
	
	private String name;
	
	private Season(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
}

一个获取季节的方法:

public static Season getSeason() {
    Season[] seasons = Season.values();
    Random r = new Random();
    int ri = r.nextInt(seasons.length);
    return seasons[ri];
}

main方法:

public static void main(String[] args) {
    Season season = getSeason();
    String msg = "现在是";
    switch (season) {
        case SPRING:
            System.out.println(msg+"春天");
            break;
        case SUMMER:
            System.out.println(msg+"夏天");
            break;
        case AUTUMN:
            System.out.println(msg+"秋天");
            break;
        case WINTER:
            System.out.println(msg+"冬天");
            break;
    }
}

五、关于枚举成员的比较是用==还是equals方法

你会发现在比较枚举成员是无论是使用==操作符还是equals方法都是可行的,那么二者究竟哪一个是对的呢?有何区别呢?关于这个问题,请看Enum类中的equals方法:

public final boolean equals(Object other) {
    return this==other;
}

可以发现,Enum类中的equals方法也仅仅是使用==操作符来进行比较。

所以使用==操作符和使用equals方法来比较枚举成员都是对的。

更多关于这个问题的讨论:

https://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals

posted @ 2019-11-05 18:12  xxx从入门到入坟  阅读(440)  评论(0)    收藏  举报