【Java】枚举类

什么是枚举

  • 从 Java 5(JDK 1.5)开始加入的语言特性,用于定义一组有限、固定的常量。当需要定义一组常量时,强烈建议使用枚举类。
  • 每个枚举常量都是 public static final(隐式)的枚举类型实例enum 实际上是继承自 java.lang.Enum<E> 的特殊类,因此不能再继承其他的类型。
  • 枚举具有类型安全,优于传统的 int/String 常量(避免魔法数字、减少出错)。
  • 枚举是线程安全且天然的单例(每个常量 JVM 只会有一个实例),并且序列化机制已经为枚举类型处理,反序列化会保持单例属性(使用 java.lang.Enum 的内部机制),因此可作为实现单例的推荐方式。通过反射无法创建新的枚举实例(java.lang.IllegalArgumentException: Cannot reflectively create enum objects)------这比普通类单例更安全。

定义枚举类

java 复制代码
[修饰符] enum 枚举类名 {
    常量对象列表(;)
}
java 复制代码
[修饰符] enum 枚举类名 {
    常量对象列表;
    
    字段/构造函数/方法
}

定义举例

java 复制代码
public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
java 复制代码
public enum Status {
    SUCCESS(200, "成功"),
    ERROR(500, "错误"),
    NOT_FOUND(404, "未找到");

    // 声明每个对象拥有的属性
    private final int code;
    private final String message;

    Status(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

注意点

  • 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。
  • 如果常量对象列表后面没有其他代码,那么;可以省略,否则不可以省略。
  • 编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明。枚举构造器不能为 publicprotected,只能 private(或默认,默认也是 private),因为枚举实例由 JVM 管理。如果枚举类需要的是有参构造,需要手动定义,调用有参构造的方法:常量对象名(实参列表)

简单使用举例

kotlin 复制代码
Status s = Status.SUCCESS;
System.out.println("Code: " + s.getCode() + ", Message: " + s.getMessage());

枚举类定义抽象方法和实现

每个常量可以有专属实现(常用于策略模式)

java 复制代码
public enum TrafficLight {
    RED(30) {
        @Override
        public TrafficLight next() { return GREEN; }
    },
    GREEN(45) {
        @Override
        public TrafficLight next() { return YELLOW; }
    },
    YELLOW(5) {
        @Override
        public TrafficLight next() { return RED; }
    };

    private final int seconds;

    TrafficLight(int seconds) {
        this.seconds = seconds;
    }

    public int getSeconds() { return seconds; }

    // 每个常量可以有不同实现(抽象方法)
    public abstract TrafficLight next();
}
java 复制代码
public enum Operation {
    ADD {
        public double apply(double x, double y) { return x + y; }
    },
    SUBTRACT {
        public double apply(double x, double y) { return x - y; }
    },
    MULTIPLY {
        public double apply(double x, double y) { return x * y; }
    },
    DIVIDE {
        public double apply(double x, double y) { return x / y; }
    };

    public abstract double apply(double x, double y);
}

枚举类实现接口与多态

枚举类可以实现一个或多个接口。

若每个枚举值在调用实现的接口方法呈现相同的行为方式,则只要统一实现该方法即可;若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法。(策略模式)

java 复制代码
interface Behaviour {
    void print();
}

public enum Season implements Behaviour {
    SPRING, SUMMER, AUTUMN, WINTER;

    @Override
    public void print() {
        System.out.println("This is " + this.name());
    }
}

策略模式

java 复制代码
public interface BinaryOperation {
    double apply(double x, double y);
}

public enum Operation implements BinaryOperation {
    PLUS {
        public double apply(double x, double y) { return x + y; }
    },
    MINUS {
        public double apply(double x, double y) { return x - y; }
    },
    TIMES {
        public double apply(double x, double y) { return x * y; }
    },
    DIVIDE {
        public double apply(double x, double y) { return x / y; }
    };
}

也可以用构造器传入 Lambda:

java 复制代码
@FunctionalInterface
public interface Strategy {
    int apply(int a, int b);
}
java 复制代码
public enum Calculator {
    ADD((a, b) -> a + b),
    SUB((a, b) -> a - b),
    MUL((a, b) -> a * b),
    DIV((a, b) -> a / b);

    private final Strategy strategy;

    Calculator(Strategy strategy) {
        this.strategy = strategy;
    }

    public int exec(int a, int b) {
        return strategy.apply(a, b);
    }
}
java 复制代码
public class Main {
    public static void main(String[] args) {
        System.out.println(Calculator.ADD.exec(3, 5));  // 8
        System.out.println(Calculator.SUB.exec(10, 2)); // 8
        System.out.println(Calculator.MUL.exec(4, 7));  // 28
        System.out.println(Calculator.DIV.exec(20, 4)); // 5
    }
}

枚举类常用方法与使用

1、static 枚举类型[] values()

返回枚举中所有常量,按声明顺序组成数组。

java 复制代码
Season[] seasons = Season.values();

2、static 枚举类型 valueOf(String name)

通过常量名获得枚举实例(区分大小写)。要求字符串必须是枚举类对象的"名字"。如不是,会发生运行时异常:IllegalArgumentException

java 复制代码
Season s = Season.valueOf("SPRING");

3、String name()

返回枚举常量的名称。

java 复制代码
s.name();   // SPRING

4、int ordinal()

返回枚举常量在枚举声明中的索引(从0开始)。

java 复制代码
s.ordinal();   // 0,1,2,3

5、String toString()

默认返回同String name(),可重写。

举例

java 复制代码
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}

public class Test {
    public static void main(String[] args) {
        // 遍历所有枚举常量
        for (Season s : Season.values()) {
            System.out.println(s + " ordinal = " + s.ordinal());
        }

        // 通过名称获取
        Season s1 = Season.valueOf("AUTUMN");
        System.out.println(s1.name());
    }
}

常与switch配合

java 复制代码
switch (season) {
    case SPRING:
        System.out.println("SPRING");
        break;
}
相关推荐
达文汐3 分钟前
【困难】力扣算法题解析LeetCode332:重新安排行程
java·数据结构·经验分享·算法·leetcode·力扣
培风图南以星河揽胜4 分钟前
Java版LeetCode热题100之零钱兑换:动态规划经典问题深度解析
java·leetcode·动态规划
启山智软28 分钟前
【中大企业选择源码部署商城系统】
java·spring·商城开发
我真的是大笨蛋30 分钟前
深度解析InnoDB如何保障Buffer与磁盘数据一致性
java·数据库·sql·mysql·性能优化
怪兽源码1 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
恒悦sunsite1 小时前
Redis之配置只读账号
java·redis·bootstrap
梦里小白龙1 小时前
java 通过Minio上传文件
java·开发语言
人道领域1 小时前
javaWeb从入门到进阶(SpringBoot事务管理及AOP)
java·数据库·mysql
sheji52612 小时前
JSP基于信息安全的读书网站79f9s--程序+源码+数据库+调试部署+开发环境
java·开发语言·数据库·算法
毕设源码-邱学长2 小时前
【开题答辩全过程】以 基于Java Web的电子商务网站的用户行为分析与个性化推荐系统为例,包含答辩的问题和答案
java·开发语言