枚举enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性,存放在 java.lang 包中。
一般用于定义同一类常量,如形容颜色的字符串常量,包含"RED"、"GREEN"、"BLUE"等。这些常量如果散落在常量类中(甚至零散的定义在各个要使用到这些常量的类中)不利于维护。
枚举的常见使用
语法
定义一个枚举使用关键字 emun
。如
public enum ColorEnum {
/**红色*/
RED,
/**绿色*/
GREEN,
/**蓝色*/
BLUE
}
public enum ColorEnum {
/**红色*/
RED("255 250 250"),
/**绿色*/
GREEN("248 248 255"),
/**蓝色*/
BLUE("220 220 220");
/**RGB色号*/
private String rgb;
ColorEnum(String rgb) {
this.rgb = rgb;
}
public String getRgb() {
return rgb;
}
}
常用方法
-
String name()
返回此枚举常量的名称
-
int ordinal()
返回枚举常量的序数(它在枚举声明中的位置,其中定义的一个枚举序数为零)
-
int compareTo(E o)
:比较此枚举与指定对象的顺序
此处的顺序是指在序数的相差位数,同一枚举时返回0,其他情况返回相减得到的值
-
Class<E>getDeclaringClass()
返回与此枚举常量的枚举类型相对应的 Class 对象。
-
String toString()
返回枚举常量的名称,它包含在声明中。
-
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
返回带指定名称的指定枚举类型的枚举常量。
-
static <T extends Enum<T>> T[] values()
返回枚举类中所有的枚举
使用上一节定义的枚举(第二种),完成对上面方法的测试。
public class ColorEnumTest {
public static void main(String[] args) {
System.out.println("name():" + ColorEnum.BLUE.name());
// name():BLUE
System.out.println("compareTo():" + ColorEnum.BLUE.compareTo(ColorEnum.RED));
// compareTo():2
System.out.println("ordinal():" + ColorEnum.RED.ordinal());
// ordinal():0
System.out.println("getDeclaringClass():" + ColorEnum.GREEN.getDeclaringClass());
// getDeclaringClass():class com.xxx.ColorEnum
System.out.println("toString():" + ColorEnum.RED.toString());
// toString():RED
System.out.println("valueOf:" + ColorEnum.valueOf("RED"));
// valueOf:RED
}
}
给 enum 自定义属性和方法
在第二种枚举类的定义中,定义了一个 String
类型的 rgb
属性,在开发过程中同样可以为枚举类定义更多类似的属性。如再增加一hex属性来描述颜色的16色。
public enum ColorEnum {
/**红色*/
RED("255 250 250", "#FFFAFA"),
/**绿色*/
GREEN("248 248 255", "#F8F8FF"),
/**蓝色*/
BLUE("220 220 220", "#DCDCDC");
/**RGB色号*/
private String rgb;
/**十六进制色号*/
private String hex;
ColorEnum(String rgb, String hex) {
this.rgb = rgb;
this.hex = hex;
}
public String getRgb() {
return rgb;
}
public String getHex() {
return hex;
}
}
在枚举常量末尾使用 ;
分割,需要定义 ColorEnum构造器
赋值,定义 get方法
获取具体的值。
枚举的本质
使用 javap
反编译ColorEnum。得到如下结果
==此处应有图片==
PS D:\code\backend\LK02.TFE_TFE9\target\classes> javap ColorEnum.class
Compiled from "ColorEnum.java"
public final class ColorEnum extends java.lang.Enum<ColorEnum> {
public static final ColorEnum RED;
public static final ColorEnum GREEN;
public static final ColorEnum BLUE;
public static ColorEnum[] values();
public static ColorEnum valueOf(java.lang.String);
public java.lang.String getRgb();
static {};
}
可以看到,枚举类通过编译,得到一个类,继承了java.lang.Enum<T>,而对于每一个枚举常量,实际上是public static final修饰的枚举类的静态实例对象。
同时注意,编译器会为我们添加两个新的static方法:values() 和 valueOf(java.lang.String),其实分别作用是返回枚举类中定义的所有的枚举常量,以及根据枚举名来获取枚举常量(注意,这里就是定义枚举常量的枚举名)。
所以对于枚举常量可以当做一组类使用,枚举常量可以当做普通的类使用
从本质看常用方法
了解了枚举的本质后,对于枚举常量的调用,name()方法、ordinal()方法等就比较好理解的了,可以看做 java.lang.Enum<T>
中定义name属性,name()等方法,在编译时为为这些属性赋值。进入到 java.lang.Enum<T>
类中,也可以看到确实是这样的
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
public final boolean equals(Object other) {
return this==other;
}
public final int hashCode() {
return super.hashCode();
}
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
protected final void finalize() { }
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}
}