枚举的基础用法

申明:本帖为对网上资源进行整理总结并结合自己的理解后重写的帖子,部分引用的源资源链接如下:

一、Enum (enumeration)

       枚举是在JDK1.5引入了新特性,在项目中经常会通过:Public static final ....来定义常量,有了枚举类之后,我们可以将同类型常量分组到一个枚举类,方便统一管理和使用。

       枚举看起来像是一种新的数据类型,实际上和正常的类相似,是一种受限的类。可以有实例变量,实例方法,静态方法,构造函数,抽象方法等等,需要注意的是:

  • Enum的构造方法为私有的,不能通过new的方法来创建,它的实例个数是有限的,不允许使用赋值符号 = 来为枚举常量赋值。枚举类不能继承,因为Enum类本身继承于 Java.lang.Enum , java语言本身不支持多重继承,所以 enum 类不能再继承其他类,当然也不能继承另一个枚举类。
  • 所有的枚举值都是 public ,static ,final的。
  • Enum 默认实现了Java.lang.Comparable 和 Serializable 接口,所以也提供 compareTo( )方法。
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable { ... }

PS:如果要为enum定义方法,那么必须在enum的最后一个实例尾部添加一个分号。此外,在enum中,必须先定义实例,不能将字段或方法定义在实例前面。否则,编译器会报错。

public enum CarType {
    //自定义枚举元素
    BMW(1,"宝马"),
    BENZ(2,"奔驰"),
    LINCOLN(3,"林肯"),
    ROLLS_ROYCE(4,"劳斯莱斯"),
    AUDI(5,"奥迪"),
    FERRARI(6,"法拉利");


    private int value;
    private String name;

    //枚举类的构造方法,注意:枚举类的构造方法只能用private来修饰
    private CarType(int value, String name)
    {
        this.value = value;
        this.name = name;
    }

    //枚举类的普通方法
    public int getValue() {
        return value;
    }

    public String getName(){
        return name;
    }

    //抽象方法
    public abstract String getDescription();

    
    //静态方法
    public static void main(String[] args) {
        for (CarType car :CarType.values() ) {
         System.out.println(car.name());
        }
    }

二、枚举类的常用方法

  1. values( )     以数组的形式返回枚举类型的所有成员。 理论上此方法可以将枚举类转变为一个枚举类型的数组,因为枚举中没有下标,我们没有办法通过下标来快速找到需要的枚举类,这时候,转变为数组之后,我们就可以通过数组的下标,来找到我们需要的枚举类。  

      

     使用实例:

      

   2.valueOf( )     将指定的普通字符串转化为枚举类型的实例

      

      

   3.name( )      返回枚举类型实例名

      

     ordinal( )     返回实例申明时的次序,从0开始

      

      

三、枚举类使用场景

1. 常量

public enum Signal{ RED, YELLOW, GREEN}

2. Switch 状态机      

因为Switch支持 int , char , String , enum类型参数,所以我们可以用 enum 来做分支判断:

enum Signal {RED, YELLOW, GREEN}

public static String getTrafficInstruct(Signal signal) {
    String instruct = "信号灯故障";
    switch (signal) {
        case RED:
            instruct = "红灯停";
            break;
        case YELLOW:
            instruct = "黄灯请注意";
            break;
        case GREEN:
            instruct = "绿灯行";
            break;
        default:
            break;
    }
    return instruct;
}

3. 枚举类中添加新的方法,以及EnumSet、EnumMap (常用方法)

Java 中提供了两个方便操作enum的工具类——EnumSet 和 EnumMap。

EnumSet 是枚举类型的高性能 Set 实现。它要求放入它的枚举常量必须属于同一枚举类型。
EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其它的 Map 实现(如HashMap)也能完成枚举类型实例到值得映射,但是使用 EnumMap 会更加高效:它只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值。这使得 EnumMap 的效率非常高。

public enum CarType {
    //枚举元素实例
    BMW(1,"宝马"),
    BENZ(2,"奔驰"),
    LINCOLN(3,"林肯"),
    ROLLS_ROYCE(4,"劳斯莱斯"),
    AUDI(5,"奥迪"),
    FERRARI(6,"法拉利");


    private int value;
    private String name;
    CarType(int value, String name)
    {
        this.value = value;
        this.name = name;
    }

    public int getValue() {
        return value;
    }

    public String getName(){
        return name;
    }

//将枚举值存入Map中,然后通过Map的 Key-value 键值对来获取想要的值
// 方法一:
private static Map<Integer, CarType> valueMap = Stream.of(CarType.values())
            .collect(Collectors.toMap(CarType::getValue, Function.identity()));

public static String getCarTypeById(int id){
        if(id == 0){
            return null;
        }
        return valueMap.get(id).toString();
    }

// 方法二:
private static Map<Integer, CarType> idToCarTypeMap = new HashMap<>();
    static {
        Arrays.stream(values()).forEach(carType -> {
            idToCarTypeMap.put(carType.value,carType);
        });
    }

public static CarType getCarType(int id){
        return idToCarTypeMap.get(id);
    }

public static String getNameById(int id){
    if(id == 0){
      return null;
      }else{
            CarType carType = idToCarTypeMap.get(id);
            String carTypeName = Optional.ofNullable(carType).map(CarType::getName).orElse("入参ID无效,无法获取指定汽车类型" );
            return carTypeName;
        }
    }

// EnumSet的用法:
System.out.println("EnumSet展示");
EnumSet<ErrorCodeEn> errSet = EnumSet.allOf(ErrorCodeEn.class);
for (ErrorCodeEn e : errSet) {
    System.out.println(e.name() + " : " + e.ordinal());
}

// EnumMap的使用
System.out.println("EnumMap展示");
EnumMap<StateMachine.Signal, String> errMap = new EnumMap(StateMachine.Signal.class);
errMap.put(StateMachine.Signal.RED, "红灯");
errMap.put(StateMachine.Signal.YELLOW, "黄灯");
errMap.put(StateMachine.Signal.GREEN, "绿灯");
for (Iterator<Map.Entry<StateMachine.Signal, String>> iter = errMap.entrySet().iterator(); iter.hasNext();) {
    Map.Entry<StateMachine.Signal, String> entry = iter.next();
    System.out.println(entry.getKey().name() + " : " + entry.getValue());
}
}

4.  枚举类实现接口及组织枚举

可以将类型相近的枚举通过接口或者类组织起来。

但是一般用接口方式进行组织。

原因是:Java接口在编译时会自动为enum类型加上public static修饰符;Java类在编译时会自动为 enum 类型加上static修饰符。看出差异了吗?没错,就是说,在类中组织 enum,如果你不给它修饰为 public,那么只能在本包中进行访问。

// 在接口中组织 enum
public interface INumberEnum {
    int getCode();
    String getDescription();
}

public enum ErrorCodeEn2 implements INumberEnum {
    OK(0, "成功"),
    ERROR_A(100, "错误A"),
    ERROR_B(200, "错误B");

    ErrorCodeEn2(int number, String description) {
        this.code = number;
        this.description = description;
    }

    private int code;
    private String description;

    @Override
    public int getCode() {
        return code;
    }

    @Override
    public String getDescription() {
        return description;
    }
}


// 在类中组织枚举
public interface Plant {
    enum Vegetable implements INumberEnum {
        POTATO(0, "土豆"),
        TOMATO(0, "西红柿");

        Vegetable(int number, String description) {
            this.code = number;
            this.description = description;
        }

        private int code;
        private String description;

        @Override
        public int getCode() {
            return 0;
        }

        @Override
        public String getDescription() {
            return null;
        }
    }

    enum Fruit implements INumberEnum {
        APPLE(0, "苹果"),
        ORANGE(0, "桔子"),
        BANANA(0, "香蕉");

        Fruit(int number, String description) {
            this.code = number;
            this.description = description;
        }

        private int code;
        private String description;

        @Override
        public int getCode() {
            return 0;
        }

        @Override
        public String getDescription() {
            return null;
        }
    }
}

5. 策略枚举(很经典的用法)

EffectiveJava中展示了一种策略枚举。这种枚举通过枚举嵌套枚举的方式,将枚举常量分类处理。

这种做法虽然没有switch语句简洁,但是更加安全、灵活。

enum PayrollDay {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
            PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(
            PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

    private final PayType payType;

    PayrollDay(PayType payType) {
        this.payType = payType;
    }

    double pay(double hoursWorked, double payRate) {
        return payType.pay(hoursWorked, payRate);
    }

    // 策略枚举
    private enum PayType {
        WEEKDAY {
            double overtimePay(double hours, double payRate) {
                return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
                        * payRate / 2;
            }
        },
        WEEKEND {
            double overtimePay(double hours, double payRate) {
                return hours * payRate / 2;
            }
        };
        private static final int HOURS_PER_SHIFT = 8;

        abstract double overtimePay(double hrs, double payRate);

        double pay(double hoursWorked, double payRate) {
            double basePay = hoursWorked * payRate;
            return basePay + overtimePay(hoursWorked, payRate);
        }
    }
}


//测试:
System.out.println("时薪100的人在周五工作8小时的收入:" + PayrollDay.FRIDAY.pay(8.0, 100));
System.out.println("时薪100的人在周六工作8小时的收入:" + PayrollDay.SATURDAY.pay(8.0, 100));

   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值