• java枚举细节


       1.在没有枚举之前,我们如果需要一些常量,比如说,我们想用一些常量来代替订单的几种状态,如已下单未付款、已付款未发货、已发货未确认收货、已收货未评价、已评价。我们会定义一个用来装常量的类,比如:

    package com.xdx.learn;
    
    public class OrderConstant {
        public static final int UNPAY=1;//未付款
        public static final int UNDELIVER=2;//未发货
        public static final int UNRECEIVE=3;//未收货
        public static final int UNCOMMENT=4;//未评价
    
    }

      在其他地方调用的时候,我们直接通过OrderConstant .UNPAY就可以获取到这个常量。

      2.有了枚举类型以后,我们会这样来写代码。

      新建一个枚举类。

      

    public enum OrderEnum {
        UNPAY("unpay",1),UNDELIVER("undeliver",2),UNRECEIVE("unreceive",3),UNCOMMENT("uncomment",4);
        private String key;
        private int value;
        private OrderEnum(String key,int value){
            this.key=key;
            this.value=value;
        }
        
        public String getKey() {
            return key;
        }
    
        public void setKey(String key) {
            this.key = key;
        }
    
        public int getValue() {
            return value;
        }
    
        public void setValue(int value) {
            this.value = value;
        }
    
        public static void main(String args[]){
            System.out.println(OrderEnum.UNPAY.getKey());
            System.out.println(OrderEnum.UNPAY.getValue());
        }
    
    }

      上面就是一个枚举类,它有如下特点。

      (1)它不用class修饰,而是用enum关键字来修饰。但是要知道的是,它本质上还是一个类。

      (2)它的构造函数不能用public修饰,只能用private来修饰,也就是说,我们不能在外部实例化一个枚举类的对象。这让你想到了什么呢?是不是单例模式。

      (3)UNPAY("unpay",1),UNDELIVER("undeliver",2),UNRECEIVE("unreceive",3),UNCOMMENT("uncomment",4);这几个都是该枚举类的对象(他们都是OrderEnum类型的),以静态常量的成员变量的形式存在于枚举类中。事实上,他们是public static final类型的,所以我们可以在类外部使用类名.成员变量,比如OrderEnum.UNPAY的形式来访问。

      (4)一旦你定义了一个枚举类,则必须也将它的实例创建出来,即是上述的UNPAY("unpay",1)这些实例。实例的创建被简化了,只需要调用构造函数,不需要用new关键字。

      其实,按照我的理解,上述的枚举类可以用以下的类来代替。

      

    package com.xdx.learn;
    
    public class OrderMulti {
        private String key;
        private int value;
        private OrderMulti(String key,int value){
            this.key=key;
            this.value=value;
        }
        
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public int getValue() {
            return value;
        }
        public void setValue(int value) {
            this.value = value;
        }
    
        public static final OrderMulti UNPAY=new OrderMulti("unpay", 1);
        public static final OrderMulti UNDELIVER=new OrderMulti("undeliver", 2);
        public static final OrderMulti UNRECEIVE=new OrderMulti("unreceive", 3);
        public static final OrderMulti UNCOMMENT=new OrderMulti("uncomment", 4);
        public static void main(String args[]){
            System.out.println(OrderMulti.UNPAY.getKey());
            System.out.println(OrderMulti.UNPAY.getValue());
        }
    
    }

      没错,枚举类就相当于一个带有多例(多例模式)的java类。只不过java的语法帮我们做了这些显式实例化的操作,并且以一种比较简单的语法来表示。就变成了enum了。

      3.再深入一点,其实枚举类都是Enum类的子类,去查jdk源码,发现Enum是一个抽象的泛型类,其定义为public abstract class Enum<E extends Enum<E>>
            implements Comparable<E>, Serializable。事实上,上述的OrderEnum类,可以理解成这样的一个类。

      public class OrderEnum extends Enum<OrderEnum>,没错,泛型的类型实参就是这个枚举类本身。

      不过当你真的在eclipse里面敲入上面的一个类,会发现报错,因为Enum这个类是不可继承的,提示的错误是The type OrderEnum may not subclass Enum<A> explicitly。不能显式的继承Enum。jdk在编译阶段就拒绝了一个类去继承Enum,具体什么原因,怎么实现,我也不知道。我们只需要知道enum修饰的类,它的父类是Enum就行了。

      既然如此,enum修饰的类也就不可以在继承其他的类了,因为java是单继承的。当然可以通过实现接口的方式去对enum类进行扩展。

      由于枚举类继承自Enum,那么Enum里面的一些方法他也可以用。看如下代码,使用了几个比较常用的方法。

      

        public static void main(String args[]){
            System.out.println(OrderEnum.UNPAY.getKey());
            System.out.println(OrderEnum.UNPAY.getValue());
            //name()方法获取该枚举类实例的名称
            System.out.println(OrderEnum.UNPAY.name());
            //ordinal()方法获取该枚举类实例在所有实例中的排序,从0开始。
            System.out.println(OrderEnum.UNPAY.ordinal());
            //compareTo()方法比较两个枚举实例的排序,可认为是前者的ordinal-后者的ordinal的值。
            System.out.println(OrderEnum.UNPAY.compareTo(OrderEnum.UNDELIVER));
            System.out.println(OrderEnum.UNRECEIVE.compareTo(OrderEnum.UNDELIVER));
            System.out.println(OrderEnum.UNCOMMENT.compareTo(OrderEnum.UNDELIVER));
            //获取该枚举对象的类
            System.out.println(OrderEnum.UNPAY.getDeclaringClass());
            //验证枚举类的父类确实是Enum
            System.out.println(OrderEnum.UNPAY.getDeclaringClass().getSuperclass());
            System.out.println(OrderEnum.UNPAY.equals(OrderEnum.UNCOMMENT));
            //遍历枚举类中实例
            for(OrderEnum orderenum:OrderEnum.values()){
                System.out.println(orderenum.getKey());
            }
        }

      上述代码的运行结果为:

      unpay
      1
      UNPAY
      0
      -1
      1
      2
      class com.xdx.learn.OrderEnum
      class java.lang.Enum
      false
      unpay
      undeliver

      unreceive
      uncomment

      4.只要将枚举理解成一个实现了多例模式的类,运用起来就不会有什么困难。但是也有人会问,我用第一种方式,即直接使用一个public static final int UNPAY=1。这样的常量。不是也可以实现枚举需要的功能吗?为何还大费周章去定义一个枚举类呢?我觉得是基于如下几方面考虑的。

      (1)首先枚举类的类名可以有一定的指示作用,比如我们给一个枚举类命名为week,我们可以知道它应该就是代表星期,而在枚举之前,我们使用常量的容器类,往往只定义一个类,命名为类似于Constant这样的类,要去里面找寻其中的常量值是比较费劲的。

      (2)当用枚举作为函数的形参的时候,能起到限定的作用。比如我有一个函数 ,我可以定义为void func(int x),接受一些常量值。我也可以定义成void func(OrderEnum orderEnum)这样的形式。后者比前者的优点在于它限制了传入的参数只能是该枚举类的实例,而前者则可以传入任意整型。

      

  • 相关阅读:
    对Spring <context:annotation-config/>的理解
    Javascript this指针
    go 打造世界最快的go模板引擎gorazor 2.0
    swagger 部署(Mac )
    Ab测试
    Nginx tcp限制并发、IP、记日志
    Nginx proxy_protocol协议与realip模块
    数据结构之回溯
    数据结构之分治
    数据结构之二分查找
  • 原文地址:https://www.cnblogs.com/roy-blog/p/7737387.html
Copyright © 2020-2023  润新知