Java基础10:枚举类

概述

  • 使用场景:
    • 类的对象只有有限个,确定的。如:星期、性别、季节
    • 当需要定义一组常量时,强烈建议使用枚举类
  • 优势:
    • 以这种方式定义的常量使代码更具可读性,允许进行编译时检查,预先记录可接受值的列表,并避免由于传入无效值而引起的意外行为

枚举类的实现

JDK1.5之前需要自定义枚举类
JDK 1.5 新增的 enum 关键字用于定义枚举类

  • 自定义枚举类
    • 私有化类的构造器,保证不能在类的外部创建其对象
    • 在类的内部创建枚举类的实例。声明为:public static final
    • 枚举类如果有属性,应该声明为private final,并在构造器中初始化
    public class Season {
    	//枚举类中的元素是确定可知,我们不希望他会发生改变,故定义private final
        private final String DESCRIBE;
    	//构造器
        private Season(String describe){
            this.DESCRIBE = describe;
        }
        //构造器
        private Season(){
            this.DESCRIBE = "no describe";
        }
    
    	//这些暴露出去全局常量就是枚举类的实际
    	//当我们需要某个季节时,只需要将对应的全局常量赋过去,保证不管在哪里
    	//都会是同一个春夏秋冬
        public static final Season SPRING = new Season("spring");
        public static final Season SUMMER = new Season("summer");
        public static final Season AUTUMN = new Season("autumn");
        public static final Season WINTER = new Season("winter");
        
    }
    
  • 使用enum定义枚举类
    • 使用 enum 定义的枚举类默认继承了 java.lang.Enum类,因此不能再继承其他类
    • 枚举类的构造器只能使用 private 权限修饰符
    • 枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的实例系统会自动添加 public static final 修饰
    • 必须在枚举类的第一行声明枚举类对象
    public enum  OrderStatus {
    	//相当于public static final OrderStatus ORDERED = new OrderStatus();
        ORDERED,
        READY(5),
        DELIVERED(0);
        
        private final int DAY_TO_DELIVER;
        
        private OrderStatus(){
            DAY_TO_DELIVER = 10;
        }
        
        private OrderStatus(int days){
            DAY_TO_DELIVER = days;
        }
    }
    

使用

  • 主要方法:
    • values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值
    • valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException
    • toString():返回当前枚举类对象常量的名称,可重写自定义更适合的输出
    • name():返回当前枚举类对象的名称,优先使用toString()方法
    • equals():枚举类型可以直接用==比较,Enum类中实现的equals()方法也是直接用 ==实现,注:该Enum中该方法是final修饰的,实现该方法是为了在List、Set、Map中使用
    • hashCode():Enum中实现了hashCode()来和equals()保持一致,它也是final修饰的
    • getDeclaringClass():返回枚举常量所属枚举类型的Class对象,用来判断两个枚举常量是否属于同一个枚举类型
    • compareTo():实现类Comparable接口,可以比较两个枚举常量大小(按照声明顺序)
    • ordinal():得到当前枚举常量的次序
    • clone():枚举类不能被克隆。为了防止子类实现克隆方法,Enum实现了一个仅抛出CloneNotSupportedException异常(运行时异常)且被final修饰的方法
    System.out.println(OrderStatus.ORDERED.name());//ORDERED
    System.out.println(OrderStatus.ORDERED.toString());//ORDERED
    //得到所有枚举常量
    OrderStatus[] orderStatuses = OrderStatus.values();
    //得到名为ORDERED的枚举常量
    OrderStatus orderStatus = OrderStatus.valueOf("ORDERED");
    //得到枚举常量所处类的类名
    System.out.println(orderStatus.getDeclaringClass());
    System.out.println(orderStatus.ordinal());//0
    
  • 使用==比较枚举类型
    • 运行时安全性
      OrderStatus orderStatus = null;
      System.out.println(orderStatus.equals(OrderStatus.ORDERED));//空指针异常
      System.out.println(orderStatus == OrderStatus.ORDERED);//正常运行
      
    • 编译时安全性
      if (OrderStatus.ORDERED.equals(TestColor.GREEN));// 编译正常
      if (OrderStatus.ORDERED == TestColor.GREEN);// 编译失败,类型不匹配
      
  • 在switch语句中使用枚举类型
    OrderStatus orderStatus = OrderStatus.ORDERED;
    switch (orderStatus){
        case ORDERED:
            System.out.println("order");
            break;
        case READY:
            System.out.println("ready");
            break;
        case DELIVERED:
            System.out.println("delivered");
            break;
        default:
            break;
    }
    
  • 枚举类方法使用
    public class Pizza {
        private PizzaStatus status;
        public enum PizzaStatus {
        	//相当于都是一个PizzaStatus匿名子类
            ORDERED (5){
                @Override
                public boolean isOrdered() {
                    return true;
                }
            },
            READY (2){
                @Override
                public boolean isReady() {
                    return true;
                }
            },
            DELIVERED (0){
                @Override
                public boolean isDelivered() {
                    return true;
                }
            };
     
            private int timeToDelivery;
     		//如果该方法被调用,说明那个枚举类常量没有重写该方法,即不是ORDERED
            public boolean isOrdered() {return false;}
     
            public boolean isReady() {return false;}
     
            public boolean isDelivered(){return false;}
     
            public int getTimeToDelivery() {
                return timeToDelivery;
            }
     
            PizzaStatus (int timeToDelivery) {
                this.timeToDelivery = timeToDelivery;
            }
        }
     
        public boolean isDeliverable() {
            return this.status.isReady();
        }
     
        public void printTimeToDeliver() {
            System.out.println("Time to delivery is " + 
              this.getStatus().getTimeToDelivery());
        }
        
        // Methods that set and get the status variable.
        
        @Test
    	public void givenPizaOrder_whenReady_thenDeliverable() {
        	Pizza testPz = new Pizza();
        	testPz.setStatus(Pizza.PizzaStatus.READY);
        	assertTrue(testPz.isDeliverable());//false
    	}
    }
    

通过枚举类实现设计模式

  • 单例模式
public enum PizzaDeliverySystemConfiguration {
    INSTANCE;
    PizzaDeliverySystemConfiguration() {
        // Initialization configuration which involves
        // overriding defaults like delivery strategy
    }
 
    private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
 
    public static PizzaDeliverySystemConfiguration getInstance() {
        return INSTANCE;
    }
 
    public PizzaDeliveryStrategy getDeliveryStrategy() {
        return deliveryStrategy;
    }
}
  • 策略模式
public enum PizzaDeliveryStrategy {
    EXPRESS {
        @Override
        public void deliver(Pizza pz) {
            System.out.println("Pizza will be delivered in express mode");
        }
    },
    NORMAL {
        @Override
        public void deliver(Pizza pz) {
            System.out.println("Pizza will be delivered in normal mode");
        }
    };
 
    public abstract void deliver(Pizza pz);
}

EnumSet和EnumMap

public class Pizza {
 
    private static EnumSet<PizzaStatus> undeliveredPizzaStatuses =
      EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);
 
    private PizzaStatus status;
 
    public enum PizzaStatus {
        ...
    }
 
    public boolean isDeliverable() {
        return this.status.isReady();
    }
 
    public void printTimeToDeliver() {
        System.out.println("Time to delivery is " + 
          this.getStatus().getTimeToDelivery() + " days");
    }
 
    public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
        return input.stream().filter(
          (s) -> undeliveredPizzaStatuses.contains(s.getStatus()))
            .collect(Collectors.toList());
    }
 
    public void deliver() { 
        if (isDeliverable()) { 
            PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
              .deliver(this); 
            this.setStatus(PizzaStatus.DELIVERED); 
        } 
    }
     
    // Methods that set and get the status variable.
}

  • EnumSet
    • EnumSet 是一种专门为枚举类型所设计的 Set 类型
    • 与HashSet相比,由于使用了内部位向量表示,因此它是特定 Enum 常量集的非常有效且紧凑的表示形式
    • 它提供了类型安全的替代方法,以替代传统的基于int的“位标志”,使我们能够编写更易读和易于维护的简洁代码
    • EnumSet 是抽象类,其有两个实现:RegularEnumSet 、JumboEnumSet,选择哪一个取决于实例化时枚举中常量的数量
    • 在很多场景中的枚举常量集合操作(如:取子集、增加、删除、containsAll和removeAll批操作)使用EnumSet非常合适;如果需要迭代所有可能的常量则使用Enum.values()
    @Test
    public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() {
        List<Pizza> pzList = new ArrayList<>();
        Pizza pz1 = new Pizza();
        pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
     
        Pizza pz2 = new Pizza();
        pz2.setStatus(Pizza.PizzaStatus.ORDERED);
     
        Pizza pz3 = new Pizza();
        pz3.setStatus(Pizza.PizzaStatus.ORDERED);
     
        Pizza pz4 = new Pizza();
        pz4.setStatus(Pizza.PizzaStatus.READY);
     
        pzList.add(pz1);
        pzList.add(pz2);
        pzList.add(pz3);
        pzList.add(pz4);
     
        List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList); 
        assertTrue(undeliveredPzs.size() == 3); 
    }
    
  • EnumMap:
    • EnumMap是一个专门化的映射实现,用于将枚举常量用作键。与对应的 HashMap 相比,它是一个高效紧凑的实现,并且在内部表示为一个数组
    @Test
    public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() {
        List<Pizza> pzList = new ArrayList<>();
        Pizza pz1 = new Pizza();
        pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
     
        Pizza pz2 = new Pizza();
        pz2.setStatus(Pizza.PizzaStatus.ORDERED);
     
        Pizza pz3 = new Pizza();
        pz3.setStatus(Pizza.PizzaStatus.ORDERED);
     
        Pizza pz4 = new Pizza();
        pz4.setStatus(Pizza.PizzaStatus.READY);
     
        pzList.add(pz1);
        pzList.add(pz2);
        pzList.add(pz3);
        pzList.add(pz4);
     
        EnumMap<Pizza.PizzaStatus,List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
        assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1);
        assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2);
        assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1);
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值