【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;
}
相关推荐
骇客野人1 小时前
JAVA日常开发技术点总结
java·开发语言
o***74171 小时前
新手如何快速搭建一个Springboot项目
java·spring boot·后端
R***z1011 小时前
Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程
java·spring boot·后端
扶苏-su1 小时前
Java---Map 接口
java·开发语言
qq_266348731 小时前
aspose处理模板,并去掉水印 jdk17
java·开发语言
f***24111 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
xunyan62341 小时前
面向对象(下)-设计模式与单例设计模式
java·单例模式·设计模式
杰克尼1 小时前
蓝桥云课-小蓝做题
java·数据结构·算法
艾莉丝努力练剑1 小时前
【C++:C++11收尾】解构C++可调用对象:从入门到精通,掌握function包装器与bind适配器包装器详解
java·开发语言·c++·人工智能·c++11·右值引用