博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java枚举类学习到进阶
阅读量:5930 次
发布时间:2019-06-19

本文共 14224 字,大约阅读时间需要 47 分钟。

枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。
△有的地方还没有学的透彻,之后会继续学习修改更新本文章

1.枚举类学习

1.1 定义枚举类

  • 枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显示继承其他父类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口。
  • 使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。
  • 枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,则默认使用private修饰;如果强制指定访问控制符,则只能指定private修饰符。
  • 枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例。列出这些实例时,系统会自动添加public static final 修饰,无须程序员显式添加。
  • 枚举类默认提供了一个values()方法,该方法可以很方便地遍历所有的枚举值。

如下定义周一到周日的常量

//Day.class//枚举类型,使用关键字enumenum Day {    MONDAY, TUESDAY, WEDNESDAY,    THURSDAY, FRIDAY, SATURDAY, SUNDAY}

相当简洁,在定义枚举类型时我们使用的关键字是enum,与class关键字类似,只不过前者是定义枚举类型,后者是定义类类型。

1.2 枚举类的实现原理

我们大概了解了枚举类型的定义与简单使用后,现在有必要来了解一下枚举类型的基本实现原理。实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类,也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类。

查看反编译Day.class文件:

//反编译Day.classfinal class Day extends Enum{    //编译器为我们添加的静态的values()方法    public static Day[] values()    {        return (Day[])$VALUES.clone();    }    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法    public static Day valueOf(String s)    {        return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);    }    //私有构造函数    private Day(String s, int i)    {        super(s, i);    }     //前面定义的7种枚举实例    public static final Day MONDAY;    public static final Day TUESDAY;    public static final Day WEDNESDAY;    public static final Day THURSDAY;    public static final Day FRIDAY;    public static final Day SATURDAY;    public static final Day SUNDAY;    private static final Day $VALUES[];    static     {            //实例化枚举实例        MONDAY = new Day("MONDAY", 0);        TUESDAY = new Day("TUESDAY", 1);        WEDNESDAY = new Day("WEDNESDAY", 2);        THURSDAY = new Day("THURSDAY", 3);        FRIDAY = new Day("FRIDAY", 4);        SATURDAY = new Day("SATURDAY", 5);        SUNDAY = new Day("SUNDAY", 6);        $VALUES = (new Day[] {            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY        });    }}
  • ①从反编译的代码可以看出编译器确实帮助我们生成了一个Day类(注意该类是final类型的,将无法被继承)而且该类继承自java.lang.Enum类,该类是一个抽象类(稍后我们会分析该类中的主要方法)。
  • ②除此之外,编译器还帮助我们生成了7个Day类型的实例对象分别对应枚举中定义的7个日期,这也充分说明了我们前面使用关键字enum定义的Day类型中的每种日期枚举常量也是实实在在的Day实例对象,只不过代表的内容不一样而已。注意编译器还为我们生成了两个静态方法,分别是values()和 valueOf()
  • ③到此我们也就明白了,使用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好变量的对应实例对象,如上述的MONDAY枚举类型对应public static final Day MONDAY;,同时编译器会为该类创建两个方法,分别是values()和valueOf()。到此相信我们对枚举的实现原理也比较清晰。下面我们深入了解一下java.lang.Enum类以及values()和valueOf()的用途。

1.3 枚举的常见方法

图片描述

2.枚举类使用

2.1常量

系统里实现常量的三种方式接口常量、类常量、枚举常量

2.1.1接口常量

如java的swing里有一个SwingConstant:

public interface SwingConstants {        /**          * The central position in an area. Used for         * both compass-direction constants (NORTH, etc.)         * and box-orientation constants (TOP, etc.).         */        public static final int CENTER  = 0;        //         // Box-orientation constant used to specify locations in a box.        //        /**          * Box-orientation constant used to specify the top of a box.         */        public static final int TOP     = 1;        /**          * Box-orientation constant used to specify the left side of a box.         */        public static final int LEFT    = 2;              //。。。省略其他代码   }

2.1.2类常量

写法(1)利弊:用到 DefaultValues.DEFAULT_AP 的含义,必须看类里的注释,知道他表示中心。如果常量很多的话,把所有的常量都放在这一个接口里边,这种方式感觉也不是很友好。

/** * 系统默认值 * */public class DefaultValues {    /**     * 默认密码     */    public static final String DEFAULT_PASSWORD = "000000";    /**     * 默认用户类型     */    public static final String DEFAULT_USER_TYPE = UserType.NormalUser.value();        /**     * 默认获取api名称     */    public static final String DEFAULT_API = "api";        /**     * 默认系统字符编码     */    public static final String DEFAULT_ENCODING = "UTF-8";        /**集群规模*/    public static final  long CLUSTER_SIZE = 1000;}

写法(2)利弊:公司的接口常量是在接口里定义静态内部类,他可以把不同的功能的常量类进一步分类。把不同功能的常量放在了接口的内部类里,通过不同的内部类可以清楚的知道一个常量的含义。

public class Constants {    public static class MimeType{        public static final String BIN = "application/octet-stream";        public static final String CSS = "text/css";        public static final String DOC = "application/msword";        public static final String DOCX = "";        public static final String EXE = "application/octet-stream";        public static final String GTAR = "application/x-gtar";        public static final String GZ = "application/x-gzip";        public static final String HTM = "text/html;charset=utf-8";        public static final String ICO = "image/x-icon";        public static final String JPEG = "image/jpeg";        public static final String JPG = "image/jpeg";        public static final String JS = "application/x-javascript;charset=utf-8";        public static final String JSON = "application/json;charset=utf-8";        public static final String FORM = "application/x-www-form-urlencoded; charset=UTF-8";        public static final String MULTIPART = "multipart/form-data; charset=UTF-8";        public static final String MHT = "message/rfc822";        public static final String MHTML = "message/rfc822";        public static final String MOV = "video/quicktime";        public static final String MP3 = "audio/mpeg";        public static final String MPE = "video/mpeg";        public static final String MPEG = "video/mpeg";        public static final String MPG = "video/mpeg";        public static final String PDF = "application/pdf";        public static final String PPT = "application/vnd.ms-powerpoint";        public static final String RTF = "application/rtf";        public static final String SWF = "application/x-shockwave-flash";        public static final String TAR = "application/x-tar";        public static final String TXT = "text/plain;charset=utf-8";        public static final String WAV = "audio/x-wav";        public static final String XML = "text/xml;charset=utf-8";        public static final String ZIP = "application/zip";            }        public static class DataState{        public static final String FLAG_REMOVE = "Y";        public static final String FLAG_NORMAL = "N";    }        /**     * 应用服务器实例运行状态     */    public static class ServerASInstanceState{        public static final int RUNNING = 1;        public static final int SHUT_OFF = 2;    }    /**     * WebServices接口分析     */    public static class WebServicesType{        /**先接收数据,在返回接口情况的接口 **/         public static final String IN_OUT = "IO";        /**先发数据请求,后返回数据的接口 **/         public static final String OUT_IN = "OI";        /**只发送数据的接口**/         public static final String OUT= "O";        /**只接收数据的接口 **/         public static final String IN = "I";    }        /**     * 任务调度使用     */    public static class TaskScheduling{        /**任务ID **/         public static final String TASK_ID = "taskID";        /**任务URL **/         public static final String TASK_URI = "taskURI";        /**任务URL **/         public static final String TASK_NAME = "taskName";        /**任务目标服务器IP **/         public static final String TASK_SERVER_IP = "taskServerIp";        /**任务目标服务器IP **/         public static final String TASK_SERVER_PORT = "taskServerPort";                /**任务状态启用**/        public static final int TASK_ENABLED = 1;                /**任务状态禁用**/        public static final int TASK_DISABLE = 0;                /**每年任务**/        public static final int TYPE_EVERY_YEAR= 1;                /**每月任务**/        public static final int TYPE_EVERY_MONTH = 2;                /**每日任务**/        public static final int TYPE_EVERY_DAY = 3;                /**每周任务**/        public static final int TYPE_EVERY_WEEK = 4;                /**单次任务**/        public static final int TYPE_SINGLE = 5;            }}

虽然有了枚举,可能是由于设计者习惯问题,还有很多人用的类常量, 定义了类常量,用一个Map<Integer, String>来封装常量对应的信息,在static代码块里,类初始化的时候执行一次put。用的时候 ResponseCode.RESP_INFO.get("DATABASE_EXCEPTION");就能取出响应信息 由于项目是前后端分离,在接口文档里需要写上状态码,还得写上状态码对应的提示信息,而且我们的响应类 RespInfo 有message属性,就是保存常量类里状态码对应的信息的。

public class ResponseCode {    /** 系统处理正常 */    public static final int SUCCESS_HEAD = 0;    /** 系统处理未知异常 */    public static final int EXCEPTION_HEAD = 1;    /** JSON解析错误 */    public static final int JSON_RESOLVE = 2;    /** 类型不匹配 */    public static final int TRANSTYPE_NO = 3;    /** Head - messageID未赋值 */    public static final int HEAD_messageID = 4;    /** Head - timeStamp未赋值 */    public static final int HEAD_timeStamp = 5;    /** Head - messengerID未赋值 */    public static final int HEAD_messengerID = 6;    /** Head - transactionType 未赋值 */    public static final int HEAD_transactionType = 7;    /** digest校验不通过 */    public static final int HEAD_DIGEST = 8;        /** src校验不通过 */    public static final int HEAD_SRC_NULL = 10;        /** 协议包含非法字符 */    public static final int ILLEGAL_MESSAGE = 11;    /** 数据库异常 */    public static final int DATABASE_EXCEPTION = 9;    public static final Map
RESP_INFO = new HashMap
(); static { // Head 相关 RESP_INFO.put(SUCCESS_HEAD, "系统处理正常"); RESP_INFO.put(EXCEPTION_HEAD, "系统处理未知异常"); RESP_INFO.put(JSON_RESOLVE, "JSON解析错误"); RESP_INFO.put(TRANSTYPE_NO, "类型不匹配"); RESP_INFO.put(HEAD_messageID, "messageID未赋值"); RESP_INFO.put(HEAD_timeStamp, "timeStamp未赋值"); RESP_INFO.put(HEAD_messengerID, "messengerID未赋值"); RESP_INFO.put(HEAD_transactionType, "transactionType未赋值"); RESP_INFO.put(HEAD_DIGEST, "digest校验不通过"); RESP_INFO.put(DATABASE_EXCEPTION, "数据库异常"); RESP_INFO.put(HEAD_SRC_NULL, "src未赋值"); RESP_INFO.put(ILLEGAL_MESSAGE, "协议包含非法字符"); }}

2.1.3枚举常量

所有的枚举类都是Enum类的子类,就行Object类一样,只是没有写出来,所以可以枚举类可调用Enum的方法。注意是逗号分隔属性,只有属性后边没有方法的话,最后加不加分号都行。

写法(1)

public enum StateType {    /**     * 成功返回状态     */    OK(200,"OK"),         /**     * 请求格式错误     */    BAD_REQUEST(400,"bad request"),    /**     * 未授权     */    UNAUTHORIZED(401,"unauthorized"),    /**     * 没有权限     */    FORBIDDEN(403,"forbidden"),        /**     * 请求的资源不存在     */    NOT_FOUND(404,"not found"),    /**     * 该http方法不被允许     */    NOT_ALLOWED(405,"method not allowed"),    /**     * 请求处理发送异常     */    PROCESSING_EXCEPTION(406,"Handling Exceptions"),    /**     *      * 请求处理未完成     */    PROCESSING_UNFINISHED(407,"To deal with unfinished"),        /**     * 登录过期     */    BEOVERDUE(408,"Be overdue"),        /**     * 用户未登录     */    NOT_LOGIN(409,"Not logged in"),        /**     * 这个url对应的资源现在不可用     */    GONE(410,"gone"),    /**     * 请求类型错误     */    UNSUPPORTED_MEDIA_TYPE(415,"unsupported media type"),    /**     * 校验错误时用     */    UNPROCESSABLE_ENTITY(422,"unprocessable entity"),    /**     * 请求过多     */    TOO_MANY_REQUEST(429,"too many request");    private int code;    private String value = null;    private StateType(int code,String value) {        this.code = code;        this.value = value;    }    public String value() {        return this.value;    }    public int getCode() {        return code;    }    public static Boolean isValidateStateType(String... stateType) {        for (int i = 0; i < stateType.length; i++) {            StateType [] value = StateType.values();            boolean falg = false;            for(StateType type : value) {                if(type.value.equals(stateType[i])) {                    falg = true;                }                            }            if(!falg) {                return falg;            }        }        return true;    }}/*使用*/public static void main(String[] args) {    System.out.println("状态码:"+StateType.getCode());        System.out.println("错误信息:"+StateType.getValue());}

写法(2)

public enum Level {    /**     * 第一层     */    One(1),    /**     * 第二层      */    Two(2),    /**     * 第三层     */    Three(3),    /**     * 第四层     */    Four(4),    /**     * 第五层     */    Five(5);        private int value;        Level(int value) {        this.value = value;    }        public int value() {        return this.value;    }        public static Boolean isValidateLevel(int level) {        Level [] value = Level.values();        boolean falg = false;        for (Level pl : value){            if(pl.value == level){                falg = true;            }        }        return falg;    }}/*使用*/public static void main(String[] args) {    System.out.println("楼层:"+Level.Three);}

2.2 switch结合枚举类

JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。

枚举是声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。枚举是将变量的值一一列出来,变量的值只局限于列举出来的值的范围内。

△注意:枚举只是枚举类型,不能够赋值操作。如下:GREEN默认值为0,但是GREEN不能=0,因为数据类型不一样。枚举中变量未直接赋值,默认等于前一个变量值加一,起始值默认为0。

enum Signal {  GREEN, YELLOW, RED } public class TrafficLight {  Signal color = Signal.RED;  public void change() {   switch (color) {   case RED:    color = Signal.GREEN;    break;   case YELLOW:    color = Signal.RED;    break;   case GREEN:    color = Signal.YELLOW;    break;   }  } }

2.3 向枚举中添加新的方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号(“;”),java中要求必须先定义java实例。

public enum ChannelEnum {    MSG_CENTER_CHANNEL1("msg_center_channel1"),    MSG_CENTER_CHANNEL("msg_center_channel");    private String channel = null;    private ChannelEnum(String channel) {        this.channel = channel;    }    public String getChannel() {        return this.channel;    }}

2.4 实现接口

  • 所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
  • 如果由枚举类来实现接口里的方法,则每个枚举值在调用该方法时都有相同的行为方式(因为方法体完全一样)。如果需要每个枚举值在调用该方法时呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法,每个枚举值提供不同的实现方式,从而让不同的枚举值调用该方法时具有不同的行为方式。
public interface Behaviour {      void print();      String getInfo();  }  public enum Color implements Behaviour{      RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);      // 成员变量      private String name;      private int index;      // 构造方法      private Color(String name, int index) {          this.name = name;          this.index = index;      }  //接口方法      @Override      public String getInfo() {          return this.name;      }      //接口方法      @Override      public void print() {          System.out.println(this.index+":"+this.name);      }  }

2.5 使用接口组织枚举

public interface Food {    enum Coffee implements Food{          BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO      }      enum Dessert implements Food{          FRUIT, CAKE, GELATO      }  }

资料原文地址:

掘金地址:

转载地址:http://niutx.baihongyu.com/

你可能感兴趣的文章
iOS开发小技巧--TableView中headerView的循环利用,以及自定义的headerView
查看>>
java向mysql插入数据乱码
查看>>
CSharpGL - Object Oriented OpenGL in C#
查看>>
【转载】ID3DXSPRITE接口简单使用
查看>>
在XML里的XSD和DTD以及standalone的使用2----具体使用详解
查看>>
常用Linux运维命令
查看>>
java 文件保存到本地
查看>>
异步数据库查询 Z
查看>>
EL表达式简介
查看>>
磁盘分区(20G升50G)
查看>>
Windows搭建测试RabbitMq遇到的问题
查看>>
分布式架构高可用架构篇_activemq高可用集群(zookeeper+leveldb)安装、配置、高可用测试...
查看>>
QT笔记之VS2012 TCP传送文件
查看>>
java批量插入数据进数据库中
查看>>
mysql无法启动ERROR! MySQL is running but PID file could not be found ?
查看>>
浅析Java.lang.ProcessBuilder类
查看>>
隐马尔科夫模型(hidden Markov model, HMM)
查看>>
Hibernate 中出现表名(XXX) is not mapped 问题
查看>>
awk打印出当前行的上一行
查看>>
【GoLang】golang 最佳实践汇总
查看>>