阅jdk并发包源码,常调用到java.util.concurrent.TimeUnit,发现如下写法有点奇怪。
public enum TimeUnit {
NANOSECONDS {
public long toNanos(long d) { return d; }
public long toMicros(long d) { return d/(C1/C0); }
public long toMillis(long d) { return d/(C2/C0); }
public long toSeconds(long d) { return d/(C3/C0); }
public long toMinutes(long d) { return d/(C4/C0); }
public long toHours(long d) { return d/(C5/C0); }
public long toDays(long d) { return d/(C6/C0); }
public long convert(long d, TimeUnit u) { return u.toNanos(d); }
int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
},
}
代码只截取了一段。但是这种写法却没见过。
原来这种块级别的写法只能出现在枚举类中,而枚举在Java中是一种特殊的类。
要想了解内部原理,最简单粗暴的方法就是反编译class文件。
public enum WeekUtil {
Monday {
@Override
public String toString() {
return "星期一";
}
@Override
boolean isRest() {
return false;
}
},
Tuesday {
@Override
public String toString() {
return "星期二";
}
@Override
boolean isRest() {
return false;
}
},
Wednesday {
@Override
public String toString() {
return "星期三";
}
@Override
boolean isRest() {
return false;
}
},
Thursday {
@Override
public String toString() {
return "星期四";
}
@Override
boolean isRest() {
return false;
}
},
Friday {
@Override
public String toString() {
return "星期五";
}
@Override
boolean isRest() {
return false;
}
},
Saturday {
@Override
public String toString() {
return "星期六";
}
@Override
boolean isRest() {
return true;
}
},
Sunday {
@Override
public String toString() {
return "星期天";
}
@Override
boolean isRest() {
return true;
}
};
abstract boolean isRest();
}
WeekUtil编译后产生8个class文件,其中一个WeekUtil文件,而WeekUtil$1.class实际上是匿名内部类,不明白内部类的,请看前文总结 Java内部类总结
实际上进一步用javap反编译得到如下结果:
很明显的看出,编译器把enum枚举类继承java.lang.Enum<E>基类,这是Jdk默认的,每个枚举类型是final定义的常量,本文提到那种写法实际上是匿名内部类的写法,如果<E>类型的枚举中出现抽象方法,则实例化枚举类型必须用匿名内部类的写法,因为enum类型是不允许被继承的。当然重写java.lang.Enum<E>的方法,也必须用匿名内部类的块级写法。
实际上java.lang.Enum<E>默认包含两个参数的构造方法,一个是枚举的字符串,一个是枚举的顺序index。
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}