文章目录
一.什么是枚举?
在java编程过程中,我们通常需要定义一些固定数量的常量,在java1.5
以前,通常的做法是定义一个静态常量类
,但自jdk1.5后,java引入了枚举(关键字enum
,全称为 enumeration,值类型),在枚举中,我们可以把相关的常量分组到一个枚举类型里
,枚举也比常量类有更多灵活的用法,使用枚举,可以有效的提高代码的整洁性、可读性、可维护性等等
二.枚举的创建
- 将类用 关键字
enum
修饰 - 枚举类中的数据每个枚举对象使用
,
隔开,最后一个枚举对象
使用;
结束。 - 可以在枚举类中声明
属性
,自定义方法
三.enum 对象的常用方法介绍
方法 | 描述 |
---|---|
int compareTo(E o) | 比较此枚举与指定对象的顺序。 |
Class getDeclaringClass() | 返回与此枚举常量的枚举类型相对应的 Class 对象。 |
String name() | 返回此枚举常量的名称,在其枚举声明中对其进行声明。 |
int ordinal() | 该方法获取的是枚举变量在枚举类中声明的顺序,下标从0开始 |
String toString() | 返回枚举常量的名称,它包含在声明中。 |
static <T extends Enum> T valueOf(Class enumType, String name) | 返回带指定名称的指定枚举类型的枚举常量。可以实现将普通字符串转换为枚举实例 |
values | 该方法可以将枚举类型成员以数组的形式返回 |
四.枚举用法
enum类当做常量类使用
//周一到周天枚举
public enum WeekEnum {
MON,TUES,WED,THURS,FRI,SAT,SUN;
}
//jdk1.7开始switch语句开始支持String类型,而jdk1.6之前只支持int,char,enum类型,使用枚举的话,能使代码的可读性大大增强
public class TestEnum {
public static void main(String[] args) {
WeekEnum week = WeekEnum.TUES;
switch (week) {
case MON:
System.out.println("星期一");
break;
case TUES:
System.out.println("星期二");
break;
case WED:
System.out.println("星期三");
break;
case THURS:
System.out.println("星期四");
break;
case FRI:
System.out.println("星期五");
break;
case SAT:
System.out.println("星期六");
break;
case SUN:
System.out.println("星期天");
break;
}
}
}
enum类中自定义方法处理枚举实例
enum AddressEnum {
HUNAN("湖南", "1101"),
GUANGDONG("广东", "1102"),
SICHUANG("四川", "1103"),
JIANGXI("江西", "1104"),;
private String address;
private String code;
private AddressEnum(String address, String code) {
this.address = address;
this.code = code;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public static String getAddressName(String addressCode){
for(AddressEnum addressEnum : AddressEnum.values()){
if(addressEnum.getCode().equals(addressCode)){
return addressEnum.getAddress();
}
}
return null;
}
public static String getAddressCode(String addressName){
for(AddressEnum addressEnum : AddressEnum.values()){
if(addressEnum.getAddress().equals(addressName)){
return addressEnum.getCode();
}
}
return null;
}
public static void main(String[] args) {
System.out.println(AddressEnum.GUANGDONG.getAddress());
System.out.println(AddressEnum.GUANGDONG.getCode());
System.out.println( AddressEnum.getAddressCode("湖南"));
System.out.println( AddressEnum.getAddressName("1102"));
}
}
//打印
//广东
//1102
//1101
//广东
enum类中定义抽象方法
与抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式,注意abstract关键字
对于枚举类来说并不是必须的如下:
public enum EnumDemo {
FIRST{
@Override
public String getInfo() {
return "FIRST TIME";
}
},
SECOND{
@Override
public String getInfo() {
return "SECOND TIME";
}
}
;
/**
* 定义抽象方法
* @return
*/
public abstract String getInfo();
//测试
public static void main(String[] args){
System.out.println("F:"+EnumDemo.FIRST.getInfo());
System.out.println("S:"+EnumDemo.SECOND.getInfo());
/**
输出结果:
F:FIRST TIME
S:SECOND TIME
*/
}
}
也可以在枚举中定义多个抽象方法, 因枚举类中有多少个抽象方法,枚举实例就要实现多少个,否则编译报错
enum类与接口
由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的
,如下:
interface food{
void eat();
}
interface sport{
void run();
}
public enum EnumDemo implements food ,sport{
FOOD,
SPORT,
; //分号分隔
@Override
public void eat() {
System.out.println("eat.....");
}
@Override
public void run() {
System.out.println("run.....");
}
}
有时候,我们可能需要对一组数据进行分类,比如进行食物菜单分类而且希望这些菜单都属于food类型,appetizer(开胃菜)、mainCourse(主菜)、dessert(点心)、Coffee等,每种分类下有多种具体的菜式或食品,此时可以利用接口来组织,如下
public enum Meal{
APPETIZER(Food.Appetizer.class),
MAINCOURSE(Food.MainCourse.class),
DESSERT(Food.Dessert.class),
COFFEE(Food.Coffee.class);
private Food[] values;
private Meal(Class<? extends Food> kind) {
//通过class对象获取枚举实例
values = kind.getEnumConstants();
}
public interface Food {
enum Appetizer implements Food {
SALAD, SOUP, SPRING_ROLLS;
}
enum MainCourse implements Food {
LASAGNE, BURRITO, PAD_THAI,
LENTILS, HUMMOUS, VINDALOO;
}
enum Dessert implements Food {
TIRAMISU, GELATO, BLACK_FOREST_CAKE,
FRUIT, CREME_CARAMEL;
}
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
LATTE, CAPPUCCINO, TEA, HERB_TEA;
}
}
}
现在我们利用一个枚举嵌套枚举的方式,把前面定义的菜谱存放到一个Meal菜单中,通过这种方式就可以统一管理菜单的数据了。
五.枚举实现的原理
实际上在枚举类被编译后,编译器会为我们生成一个对应的class类
,且这个类继承java.lang.Enum类
//位于EnumDemo.java文件
public class EnumDemo {
public static void main(String[] args){
//直接引用
Day day =Day.MONDAY;
}
}
//定义枚举类型
enum Day {
MONDAY, TUESDAY, WEDNESDAY,THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
利用javac
编译的EnumDemo.java
文件后分别生成了Day.class和EnumDemo.class文件
,而Day.class
就是枚举类型
,这验证前面所说的枚举类被编译后,编译器会自动帮助我们生成一个与枚举类相关的class类。
我们再来看看反编译Day.class文件:
//反编译Day.class
final class Day extends Enum{
//编译器为我们添加的静态的values()方法
public static Day[] values(){
return (Day[])$VALUES.clone();
}
//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
public static Day valueOf(String s) {
return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
}
//私有构造函数
private Day(String s, int i){
super(s, i);
}
//前面定义的7种枚举实例
public static final Day MONDAY;
public static final Day TUESDAY;
public static final Day WEDNESDAY;
public static final Day THURSDAY;
public static final Day FRIDAY;
public static final Day SATURDAY;
public static final Day SUNDAY;
private static final Day $VALUES[];
static {
//实例化枚举实例
MONDAY = new Day("MONDAY", 0);
TUESDAY = new Day("TUESDAY", 1);
WEDNESDAY = new Day("WEDNESDAY", 2);
THURSDAY = new Day("THURSDAY", 3);
FRIDAY = new Day("FRIDAY", 4);
SATURDAY = new Day("SATURDAY", 5);
SUNDAY = new Day("SUNDAY", 6);
$VALUES = (new Day[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
}
- 从反编译的代码可以看出编译器确实生成了一个Day类
(该类是final类型的,将无法被继承)
且该类继承自java.lang.Enum类
- 该类是一个抽象类,除此之外
编译器还生成了7个Day类型的实例对象
分别对应枚举中定义的7个日期 - 这说明了我们使用关键字enum定义的Day类型中的每种日期枚举常量都是
Day实例对象
,只不过对象属性值不一样。 同时编译器还生成了两个静态方法,分别是values()和 valueOf()
,用于获取枚举实例对象。 - 因此,使用关键字enum定义的枚举类型,在编译期后将转换成为class类,在该类中,会存在每个在枚举类型中定义好变量的
对应实例对象
,且每个对象都是final修饰的不可变对象。如上述的MONDAY枚举类型
对应public static final Day MONDAY