Java中定义的所有enum类型,实际上都继承了java.lang.Enum类。首先,将Enum类源码贴在这里:
package java.lang;
import java.io.Serializable;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
public abstract class Enum>
implements Comparable, 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 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 getDeclaringClass() {
Class> clazz = getClass();
Class> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class)clazz : (Class)zuper;
}
public static > T valueOf(Class 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");
}
}
1、为什么类的声明这么奇怪,是Enum
这种声明限制了,要显式继承Enum类的话,只能使用这种方式:class SubClass extends Enum
声明成Enum
2、getDeclaringClass的方法体怎么这么奇怪?
Enum是一个抽象类,不能声明实例。要把这个方法当做其实现类的方法来看待。
仍然沿用上面的,假设有这样一个类:class SubClass extends Enum
为什么这么奇怪呢,如果直接使用getClass(),返回的不也是SubClass.class吗?这说明,还是有zuper不等于Enum.class的情况出现的。详细的见下面的解析。
语法糖:新语法A的编译结果,和老语法B的编译结果一样,但A语法出现更晚,用起来也更简单,就可以认为A是一个语法糖。语法糖并没有为这种语言增加任何新的特性。
enum实际上就是一种语法糖,它的编译到底等效于一种什么样的写法呢?
例如有这样一个类:enum Gender { MALE, FEMALE }
编译之后,等效于这个类。枚举值实际上就是这个类的public static final字段。
public final class Gender extends Enum {
public static final Gender MALE;
public static final Gender FEMALE;
private static final Gender[] $VALUES;
static {
MALE = new Gender("MALE", 0);
FEMALE = new Gender("FEMALE", 1);
$VALUES = new Gender[] {Male, Female};
}
private Gender(String name, int original) {
super(name, original);
}
public static Gender[] values() {
return $VALUE.clone();
}
public static Gender valueOf(String name) {
return Enum.valueOf(Gender.class, name);
}
}
再来看复杂一些。如果我们在Gender枚举中加上几个字段呢:
public enum Gender {
MALE(1, 3), FEMALE(7, 8);
private final int a;
private final int b;
Gender(int a, int b) {
this.a = a;
this.b = b;
}
public int getA() { return a; }
public int getB() { return b; }
}
猜想会出现以下的变化:
public final class Gender extends Enum {
private int a;
private int b;
public static final Gender MALE;
public static final Gender FEMALE;
private static final Gender[] $VALUES;
static {
MALE = new Gender("MALE", 0, 1, 3);
FEMALE = new Gender("FEMALE", 1, 7, 8);
$VALUES = new Gender[] {Male, Female};
}
private void $Gender(int a, int b) {
this.a = a;
this.b = b;
}
public int getA() { return a; }
public int getB() { return b; }
private Gender(String name, int original, int a, int b) {
super(name, original);
$Gender(a, b);
}
public static Gender[] values() {
return $VALUE.clone();
}
public static Gender valueOf(String name) {
return Enum.valueOf(Gender.class, name);
}
}
让枚举带上一个方法:
enum GenderA {
MALE {
@Override
public int getName() {
return 3;
}
},
FEMALE {
@Override
public int getName() {
return 90;
}
};
public abstract int getName();
}
这下,编译出来的结果就不一样了。上面的枚举编译出来,只有1个class文件,而这个枚举编译出了3个class文件:GenderA.class GenderA$1.class GenderA$2.class
此时,GenderA不再是一个普通类,而是一个abstract类(因为有没实现的getName方法),两个枚举值各是一个GenderA的派生类,对getName方法的实现不一样。
由此可以返回到getDeclaringClass方法的问题。
public final Class getDeclaringClass() {
Class> clazz = getClass();
Class> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class)clazz : (Class)zuper;
}
如果是不带有abstract方法的枚举类,clazz就是枚举类,zuper就是Enum.class。
如果是带有abstract方法的枚举类,clazz就是GenderA$1.class这种匿名类,而zuper才是枚举类。