1. 引言
因为在项目中,经常会会用到枚举类型。
然后并不清楚枚举类型的使用情景,还有更多的使用习惯。所以在此总结一下。
PS : 新的博客内容,一定要加上目录,要不以后看真不知道自己当时整理了啥。
2. Overview
The enum keyword was introduced in Java 5
Constants defined this way make the code more readable
2.1 枚举的典型应用场景
错误码、状态机等
将常量放到一起,便于管理。
2.2 枚举的本质
其实就是枚举Enum的子类
2.3 怎么看java编译出的class
javac xxx.java 来生成.class
javap xxx.class 们可以查看java编译器生成的字节码,然后用于分解class文件
可以看到java的一些信息
3. abstract class Enum(源码)
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");
}
}
4. doc describe
-
Constructor Summary
Constructors Modifier Constructor and Description protected
Enum(String name, int ordinal)
Sole constructor.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method and Description protected Object
clone()
Throws CloneNotSupportedException.
int
compareTo(E o)
Compares this enum with the specified object for order.
boolean
equals(Object other)
Returns true if the specified object is equal to this enum constant.
protected void
finalize()
enum classes cannot have finalize methods.
Class<E>
getDeclaringClass()
Returns the Class object corresponding to this enum constant's enum type.
int
hashCode()
Returns a hash code for this enum constant.
String
name()
Returns the name of this enum constant, exactly as declared in its enum declaration.
int
ordinal()
Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero).
String
toString()
Returns the name of this enum constant, as contained in the declaration.
static <T extends Enum<T>>
TvalueOf(Class<T> enumType, String name)
Returns the enum constant of the specified enum type with the specified name.
5. 枚举的使用
5.1 遍历
可以把枚举类型toString();来让他作为String
package a;
public enum FruitEnum {
APPLE,
PEAR,
peach;
//相当于调用Enum(String name, int ordinal):
//相当于 new Enum<FruitEnum>("APPLE",0); pear也是一样
public static void main(String[] args) {
for (FruitEnum e : FruitEnum.values()) {
System.out.println(e.toString());
}
}
}
5.2 静态枚举?
What's the difference between static and non-static enum in Java?
they are implicitly static
by default.
其实他们都是隐式的static的,所以用不用static修饰都行,毕竟是常量
Nested enum types are implicitly static. It is permissible to explicitly declare a nested enum type to be static.
嵌套的枚举类都是静态的。
5.3 关于int
ordinal()
int
ordinal()
: 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
这个是我一直比较困惑的点。
其实
public enum FruitEnum {
APPLE,
PEAR,
peach;
}
是有这个顺序的默认是0
默认构造函数是
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
所以上述使用就相当于存了一些String的变量
实际上 enum 就是一个 class,只不过 java 编译器帮我们做了语法的解析和编译
5.4 getDeclaringClass()
package a;
public enum FruitEnum {
APPLE,
PEAR,
PEACH;
public static void main(String[] args) {
FruitEnum fruitEnum = FruitEnum.APPLE;
System.out.println(fruitEnum.getDeclaringClass());
}
}
输出: class a.FruitEnum
目的:返回实例所属的 enum 类型
源码:
/**
* Returns the Class object corresponding to this enum constant's
* enum type. Two enum constants e1 and e2 are of the
* same enum type if and only if
* e1.getDeclaringClass() == e2.getDeclaringClass().
* (The value returned by this method may differ from the one returned
* by the {@link Object#getClass} method for enum constants with
* constant-specific class bodies.)
*
* @return the Class object corresponding to this enum constant's
* enum type
*/
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
所以就是: Returns the Class object corresponding to this enum constant'senum type
5.5 判等操作
package a;
public enum FruitEnum {
APPLE,
PEAR,
PEACH;
public static void main(String[] args) {
FruitEnum fruitEnum = FruitEnum.APPLE;
System.out.println("APPLE name(): " + fruitEnum.name());
System.out.println("APPLE getDeclaringClass(): " + fruitEnum.getDeclaringClass());
System.out.println("APPLE hashCode(): " + fruitEnum.hashCode());
System.out.println("equals APPLE: " + fruitEnum.compareTo(fruitEnum.APPLE));
System.out.println("equals PEACH: " + fruitEnum.equals(fruitEnum.PEACH));
System.out.println("equals 与0判断: " + fruitEnum.equals(0));
System.out.format("== 判断: %b\n", fruitEnum == fruitEnum.APPLE);
}
}
输出结果:
APPLE name(): APPLE
APPLE getDeclaringClass(): class a.FruitEnum
APPLE hashCode(): 1554547125
equals APPLE: 0
equals PEACH: false
equals 与0判断: false
== 判断: true
5.6 其他相关知识
参考:
public enum ErrorCodeEn {
OK(0) {
@Override
public String getDescription() {
return "成功";
}
},
ERROR_A(100) {
@Override
public String getDescription() {
return "错误A";
}
},
ERROR_B(200) {
@Override
public String getDescription() {
return "错误B";
}
};
private int code;
// 构造方法:enum的构造方法只能被声明为private权限或不声明权限
private ErrorCodeEn(int number) { // 构造方法
this.code = number;
}
public int getCode() { // 普通方法
return code;
} // 普通方法
public abstract String getDescription(); // 抽象方法
public static void main(String args[]) { // 静态方法
for (ErrorCodeEn s : ErrorCodeEn.values()) {
System.out.println("code: " + s.getCode() + ", description: " + s.getDescription());
}
}
}
// Output:
// code: 0, description: 成功
// code: 100, description: 错误A
// code: 200, description: 错误B
可以这样定义枚举~
5.7 策略枚举
Effective Java 中展示了一种策略枚举。这种枚举通过枚举嵌套枚举的方式,将枚举常量分类处理。
这种做法虽然没有 switch 语句简洁,但是更加安全、灵活。
例:EffectvieJava 中的策略枚举范例
enum PayrollDay {
MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(
PayType.WEEKEND), SUNDAY(PayType.WEEKEND);
private final PayType payType;
PayrollDay(PayType payType) {
this.payType = payType;
}
double pay(double hoursWorked, double payRate) {
return payType.pay(hoursWorked, payRate);
}
// 策略枚举
private enum PayType {
WEEKDAY {
double overtimePay(double hours, double payRate) {
return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
* payRate / 2;
}
},
WEEKEND {
double overtimePay(double hours, double payRate) {
return hours * payRate / 2;
}
};
private static final int HOURS_PER_SHIFT = 8;
abstract double overtimePay(double hrs, double payRate);
double pay(double hoursWorked, double payRate) {
double basePay = hoursWorked * payRate;
return basePay + overtimePay(hoursWorked, payRate);
}
}
}
复制代码
测试
System.out.println("时薪100的人在周五工作8小时的收入:" + PayrollDay.FRIDAY.pay(8.0, 100));
System.out.println("时薪100的人在周六工作8小时的收入:" + PayrollDay.SATURDAY.pay(8.0, 100));
5.8 总结
enum 是一个普通的 class,它们都可以定义一些属性和方法
不同之处是:enum 不能使用 extends 关键字继承其他类,因为 enum 已经继承了 java.lang.Enum
如果枚举中没有定义方法,也可以在最后一个实例后面加逗号、分号或什么都不加。
如果枚举中没有定义方法,枚举值默认为从 0 开始的有序数值。