Java 枚举

Java 枚举

枚举的基本定义与规范

枚举类型用于定义一个固定的枚举值列表,每个值为标识符。

定义格式

enum MyFavoriteColor{RED, BLUE, GREEN, YELLOW}

命名规范

  • 枚举值:类似常量,惯例使用全部大写字母(如 RED、BLUE)
  • 枚举类型:命名规则同类名,每个单词首字母大写(如 MyFavoriteColor)

变量声明

定义枚举类型后,可声明该类型变量:

MyFavoriteColor color;

枚举的核心作用与目的

  • 取值限制:枚举类型的变量取值只能是预定义的枚举值或 null,不允许其他非法值
  • 编译时校验:编译器在编译阶段即可拦截非法值,保证类型安全
  • 对比普通变量:普通变量无法在开发阶段限制取值范围,存在非法值风险

注意:引用枚举值时,必须使用枚举类型名称作为限定词(如 MyFavoriteColor.BLUE

用普通类模拟枚举功能

枚举的底层本质是特殊类,可通过普通类手动模拟其核心特性,需满足以下条件:

  1. 私有构造方法(禁止外部通过 new 创建实例)
  2. 枚举元素以公共静态常量形式定义(每个元素都是自身实例)
  3. 可定义公共方法或抽象方法

基础版本(含大量 if-else)

package com.sss;

/**
 * @author Jing61
 * 枚举类
 * 构造方法私有
 * 成员变量必须是static final
 */
public class WeekDay {
    // 枚举元素(静态常量)
    public static final WeekDay MONDAY = new WeekDay();
    public static final WeekDay TUESDAY = new WeekDay();
    public static final WeekDay WEDNESDAY = new WeekDay();
    public static final WeekDay THURSDAY = new WeekDay();
    public static final WeekDay FRIDAY = new WeekDay();
    public static final WeekDay SATURDAY = new WeekDay();
    public static final WeekDay SUNDAY = new WeekDay();

    /**
     * 私有构造方法,禁止外部new
     */
    private WeekDay() {}

    @Override
    public String toString() {
        if (this == MONDAY) return "星期一";
        else if (this == TUESDAY) return "星期二";
        else if (this == WEDNESDAY) return "星期三";
        else if (this == THURSDAY) return "星期四";
        else if (this == FRIDAY) return "星期五";
        else if (this == SATURDAY) return "星期六";
        else return "星期日";
    }

    // 返回枚举值索引(类似原生枚举的ordinal())
    public int ordinal() {
        if (this == MONDAY) return 0;
        else if (this == TUESDAY) return 1;
        else if (this == WEDNESDAY) return 2;
        else if (this == THURSDAY) return 3;
        else if (this == FRIDAY) return 4;
        else if (this == SATURDAY) return 5;
        else return 6;
    }

    // 返回下一天(示例方法)
    public WeekDay nextDay() {
        if (this == MONDAY) return TUESDAY;
        else if (this == TUESDAY) return WEDNESDAY;
        else if (this == WEDNESDAY) return THURSDAY;
        else if (this == THURSDAY) return FRIDAY;
        else if (this == FRIDAY) return SATURDAY;
        else if (this == SATURDAY) return SUNDAY;
        else return MONDAY;
    }
}

优化版本(抽象方法 + 匿名内部类)

解决基础版本中 if-else 冗余问题,每个枚举元素独立实现抽象方法:

package com.sss;

/**
 * @author Jing61
 * 枚举类(抽象类版本)
 * 构造方法私有
 * 成员变量必须是static final
 */
public abstract class WeekDay {
    // 枚举元素(匿名内部类实现抽象方法)
    public static final WeekDay MONDAY = new WeekDay() {
        @Override
        public int ordinal() { return 0; }
        @Override
        public WeekDay nextDay() { return TUESDAY; }
    };

    public static final WeekDay TUESDAY = new WeekDay() {
        @Override
        public int ordinal() { return 1; }
        @Override
        public WeekDay nextDay() { return WEDNESDAY; }
    };

    public static final WeekDay WEDNESDAY = new WeekDay() {
        @Override
        public int ordinal() { return 2; }
        @Override
        public WeekDay nextDay() { return THURSDAY; }
    };

    public static final WeekDay THURSDAY = new WeekDay() {
        @Override
        public int ordinal() { return 3; }
        @Override
        public WeekDay nextDay() { return FRIDAY; }
    };

    public static final WeekDay FRIDAY = new WeekDay() {
        @Override
        public int ordinal() { return 4; }
        @Override
        public WeekDay nextDay() { return SATURDAY; }
    };

    public static final WeekDay SATURDAY = new WeekDay() {
        @Override
        public int ordinal() { return 5; }
        @Override
        public WeekDay nextDay() { return SUNDAY; }
    };

    public static final WeekDay SUNDAY = new WeekDay() {
        @Override
        public int ordinal() { return 6; }
        @Override
        public WeekDay nextDay() { return MONDAY; }
    };

    /**
     * 私有构造方法,禁止外部new
     */
    private WeekDay() {}

    @Override
    public String toString() {
        if (this == MONDAY) return "星期一";
        else if (this == TUESDAY) return "星期二";
        else if (this == WEDNESDAY) return "星期三";
        else if (this == THURSDAY) return "星期四";
        else if (this == FRIDAY) return "星期五";
        else if (this == SATURDAY) return "星期六";
        else return "星期日";
    }

    /**
     * 抽象方法:返回枚举值索引
     * @return 索引值
     */
    public abstract int ordinal();

    /**
     * 抽象方法:返回下一天
     * @return 下一个星期枚举值
     */
    public abstract WeekDay nextDay();
}

增强版本(含成员变量与 getter/setter)

枚举类可添加成员变量、构造方法和普通方法:

package com.sss;

/**
 * @author Jing61
 * 枚举类(带成员变量版本)
 */
public abstract class WeekDay {
    private String name; // 成员变量

    // 枚举元素(传入成员变量值)
    public static final WeekDay MONDAY = new WeekDay("星期一") {
        @Override
        public int ordinal() { return 0; }
        @Override
        public WeekDay nextDay() { return TUESDAY; }
    };

    public static final WeekDay TUESDAY = new WeekDay("星期二") {
        @Override
        public int ordinal() { return 1; }
        @Override
        public WeekDay nextDay() { return WEDNESDAY; }
    };

    // 其他枚举元素(WEDNESDAY ~ SUNDAY)省略,同优化版本...

    /**
     * 私有构造方法(无参)
     */
    private WeekDay() {}

    /**
     * 私有构造方法(带参数)
     * @param name 星期名称
     */
    private WeekDay(String name) {
        this.name = name;
    }

    // getter/setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 其他方法(toString、ordinal、nextDay)省略,同优化版本...
}

原生枚举的使用(enum 关键字)

Java 提供 enum 关键字简化枚举定义,无需手动实现核心逻辑,原生支持多种特性。

简单枚举定义

package com.sss;

/**
 * @author Jing61
 * 简单枚举示例
 */
public enum MyFavoriteColor {
    RED,    // 枚举值(默认是public static final)
    BLUE,
    GREEN,
    YELLOW,
    ORANGE,
    PURPLE,
    PINK,
    BROWN,
    BLACK,
    WHITE;
}

枚举的继承特性

  • 枚举类型默认继承 java.lang.Enum 类(间接继承 Object
  • 实现 java.lang.Comparable 接口
  • 继承 Object 的所有方法(如 toString()equals()
  • 继承 Enum 的核心方法(如 name()ordinal()

枚举的核心方法

方法签名 功能说明
public String name() 返回枚举值的名称(与定义时一致)
public int ordinal() 返回枚举值的序号(从 0 开始,按定义顺序递增)
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 将字符串转换为对应的枚举值(名称必须完全匹配)
public static T[] values() 返回该枚举类型的所有值(数组形式,按定义顺序排列)

简单枚举测试

package com.sss;

/**
 * @author Jing61
 * 枚举测试类
 */
public class EnumTest {
    public static void main(String[] args) {
        // 1. 声明枚举变量(不能通过new创建)
        MyFavoriteColor color = MyFavoriteColor.BLUE;

        // 2. 调用枚举方法
        System.out.println(color);          // 输出:BLUE(重写了toString())
        System.out.println(color.name());   // 输出:BLUE(返回枚举名)
        System.out.println(color.ordinal());// 输出:1(BLUE是第二个值,序号从0开始)
        System.out.println(MyFavoriteColor.valueOf("BLUE")); // 输出:BLUE(字符串转枚举)
    }
}

复杂枚举(带数据域、构造方法和抽象方法)

原生枚举支持添加成员变量、构造方法(默认私有)、普通方法和抽象方法。

示例:交通灯枚举

package com.sss;

/**
 * 交通灯枚举(复杂枚举示例)
 * @author Jing61
 */
public enum TrafficLamp {
    // 枚举值:必须在最前面,带参数(对应构造方法),末尾加逗号/分号
    RED(30) {
        @Override
        public void show() { // 实现抽象方法
            System.out.println("红灯亮,禁止通行");
        }
    },
    YELLOW(5) {
        @Override
        public void show() {
            System.out.println("黄灯亮,准备停车");
        }
    },
    GREEN(60) {
        @Override
        public void show() {
            System.out.println("绿灯亮,可以通行");
        }
    };

    // 成员变量(灯持续时间,单位:秒)
    private int time;

    /**
     * 构造方法(默认私有,可省略private关键字)
     * @param time 灯持续时间
     */
    TrafficLamp(int time) {
        this.time = time;
    }

    /**
     * 普通方法:获取灯持续时间
     * @return 持续时间(秒)
     */
    public int getTime() {
        return time;
    }

    /**
     * 抽象方法:每个枚举值必须实现
     */
    public abstract void show();
}

枚举测试

package com.sss;

/**
 * 交通灯枚举测试
 * @author sss
 */
public class TrafficLampTest {
    public static void main(String[] args) {
        // 1. 字符串转枚举
        String lampName = "RED";
        TrafficLamp redLamp = TrafficLamp.valueOf(lampName);
        System.out.println("红灯持续时间:" + redLamp.getTime()); // 输出:30
        redLamp.show(); // 输出:红灯亮,禁止通行

        // 2. 遍历所有枚举值(使用values()方法)
        TrafficLamp[] allLamps = TrafficLamp.values();
        
        // foreach循环(推荐)
        System.out.println("\n所有交通灯:");
        for (TrafficLamp lamp : allLamps) {
            System.out.print(lamp + "(" + lamp.getTime() + "秒):");
            lamp.show();
        }

        // 普通for循环
        System.out.println("\n交通灯序号与时间:");
        for (int i = 0; i < allLamps.length; i++) {
            TrafficLamp lamp = allLamps[i];
            System.out.println("序号" + lamp.ordinal() + ":" + lamp.getName() + "," + lamp.getTime() + "秒");
        }
    }
}

枚举的遍历方式

foreach 循环

通过 values() 方法获取枚举数组,遍历更简洁:

for (TrafficLamp lamp : TrafficLamp.values()) {
    System.out.println(lamp + ":" + lamp.getTime() + "秒");
}

普通 for 循环

TrafficLamp[] lamps = TrafficLamp.values();
for (int i = 0; i < lamps.length; i++) {
    System.out.println(lamps[i].name() + ",序号:" + lamps[i].ordinal());
}
posted @ 2025-11-21 09:17  Jing61  阅读(4)  评论(0)    收藏  举报