enum_enumerate - CSDN
enum 订阅
enum是计算机编程语言中的一种数据类型。枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等。如果把这些量说明为整型,字符型或其它类型显然是不妥当的。为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。 展开全文
enum是计算机编程语言中的一种数据类型。枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等。如果把这些量说明为整型,字符型或其它类型显然是不妥当的。为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。
信息
所属学科
计算机
外文名
ENUM
类    属
数据类型
中文名
枚举
应用领域
计算机编程
ENUM定义说明
1. 枚举类型定义的一般形式为:enum 枚举名{ 枚举值表 };在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。例如:该枚举名为weekday,枚举值共有7个,即一周中的七天。凡被说明为weekday类型变量的取值只能是七天中的某一天。2. 枚举变量的说明如同结构体(struct)和共用体(union)一样,枚举变量也可用不同的方式说明,即先定义后说明,同时定义说明或直接说明。设有变量a,b,c被说明为上述的weekday,可采用下述任一种方式:
收起全文
精华内容
参与话题
  • C语言enum枚举类型解析

    万次阅读 多人点赞 2014-04-01 15:37:46
    在实际应用中,有的变量只有几种可能取值。如人的性别只有两种可能取值,星期只有七种可能取值。在 C 语言中对这样取值比较特殊的变量可以定义为枚举类型。...enum weekday{sun,mon,tue,wed,thu,fri

    在实际应用中,有的变量只有几种可能取值。如人的性别只有两种可能取值,星期只有七种可能取值。在 C 语言中对这样取值比较特殊的变量可以定义为枚举类型。所谓枚举是指将变量的值一一列举出来,变量只限于列举出来的值的范围内取值。 
    定义一个变量是枚举类型,可以先定义一个枚举类型名,然后再说明这个变量是该枚举类型。

    例如: 
    enum weekday{sun,mon,tue,wed,thu,fri,sat}; 
    定义了一个枚举类型名 enum weekday,然后定义变量为该枚举类型。例如: 
    enum weekday day; 
    当然,也可以直接定义枚举类型变量。例如: 
    enum weekday{sun,mon,tue,wed,thu,fri,sat} day; 
    其中,sum,mon,…,sat 等称为枚举元素或枚举常量,它们是用户定义的标识符。 
    需要说明的有以下几点。 
    ① 枚举元素不是变量,而是常数,因此枚举元素又称为枚举常量。因为是常量,所以不能对枚举元素进行赋值。 
    ② 枚举元素作为常量,它们是有值的,C 语言在编译时按定义的顺序使它们的值为,1,2,…。 
    在上面的说明中,sun 的值为 0,mon 的值为 1,…sat 的值为 6,如果有赋值语句 
    day=mon; 
    则 day 变量的值为 1。当然,这个变量值是可以输出的。例如: 
    printf ("%d",day); 
    将输出整数 1。 
    如果在定义枚举类型时指定元素的值,也可以改变枚举元素的值。例如: 
    enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat}day; 
    这时,sun 为 7,mon 为 1,以后元素顺次加 1,所以 sat 就是 6 了。 
    ③ 枚举值可以用来作判断。例如: 
    if (day==mon) {…} 
    if (day>mon) {…} 
    枚举值的比较规则是:按其在说明时的顺序号比较,如果说明时没有人为指定,则第一个枚举元素的值认作 0。例如,mon>sun,sat>fri。 
    C 语言教程 ?216? 
    ④ 一个整数不能直接赋给一个枚举变量,必须强制进行类型转换才能赋值。例如: 
    day=(enum weekday)2; 
    这个赋值的意思是,将顺序号为 2 的枚举元素赋给 day,相当于workday=tue; 
    【例 11.6】从键盘输入一个整数,显示与该整数对应的枚举常量的英文名称。 
    # include 
    void main( ) 

    enum weekday {sun,mon,tue,wed,thu,fri,sat} day; 
    int k; 
    printf("input a number(0--6)"); 
    scanf("%d",&k); 
    day=(enum weekday)k; 
    switch(day) 

    case sun: printf("sunday/n");break; 
    case mon: printf("monday/n");break; 
    case tue: printf("tuesday/n");break; 
    case wed: printf("wednesday/n");break; 
    case thu: printf("thursday/n");break; 
    case fri: printf("friday/n");break; 
    case sat: printf("satday/n");break; 
    default: printf("input error/n");break; 


    程序运行结果为: 
    input a number(0--6)1 
    monday 
    在该程序中,枚举常量与枚举变量可以进行比较,但要输出枚举常量对应的英文单词,不能使用以下语句: 
    printf(" %s",mon); 
    因为枚举常量 mon 为整数值,而非字符串。 
    在使用枚举变量时,主要关心的不是它的值的大小,而是其表示的状态。

     

    ------------------------------------------------------------------

    注:以下全部代码的执行环境为VC++ 6.0

    在程序中,可能需要为某些整数定义一个别名,我们可以利用预处理指令#define来完成这项工作,您的代码可能是:


    #define MON  1
    #define TUE   2
    #define WED  3
    #define THU   4
    #define FRI    5
    #define SAT   6
    #define SUN   7

     

    在此,我们定义一种新的数据类型,希望它能完成同样的工作。这种新的数据类型叫枚举型。

     

    1. 定义一种新的数据类型 - 枚举型

    以下代码定义了这种新的数据类型 - 枚举型


    enum DAY
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    };

     

    (1) 枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。

    (2) DAY是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。

    (3) 第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。

    (4) 可以人为设定枚举成员的值,从而自定义某个范围内的整数。

    (5) 枚举型是预处理指令#define的替代。

    (6) 类型定义以分号;结束。

     

    2. 使用枚举类型对变量进行声明

    新的数据类型定义完成后,它就可以使用了。我们已经见过最基本的数据类型,如:整型int, 单精度浮点型float, 双精度浮点型double, 字符型char, 短整型short等等。用这些基本数据类型声明变量通常是这样:


    char     a; //变量a的类型均为字符型char
    char     letter;
    int        x,
               y,
               z; //变量x,y和z的类型均为整型int
    int       number;
    double  m, n;
    double  result; //变量result的类型为双精度浮点型double

     

    既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。

    方法一:枚举类型的定义和变量的声明分开


    enum DAY
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    };

     


    enum DAY yesterday;
    enum DAY today;
    enum DAY tomorrow; //变量 tomorrow的类型为枚举型enum DAY
    enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum DAY

     

    方法二:类型定义与变量声明同时进行:


    enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。
    {
        saturday,
        sunday = 0,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    } workday; //变量workday的类型为枚举型enum DAY

     


    enum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days; //变量days的类型为枚举型enum week

     


    enum BOOLEAN { false, true } end_flag, match_flag; //定义枚举类型并声明了两个枚举型变量

     

    方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明:


    typedef enum workday
    {
        saturday,
        sunday = 0,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    } workday; //此处的workday为枚举型enum workday的别名

     


    workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday

     

    enum workday中的workday可以省略:


    typedef enum
    {
        saturday,
        sunday = 0,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    } workday; //此处的workday为枚举型enum workday的别名
    workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即 enum workday

     

    也可以用这种方式:


    typedef enum workday
    {
        saturday,
        sunday = 0,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    };
    workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即 enum workday

     

    注意:同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。错误示例如下所示:

    错误声明一:存在同名的枚举类型


    typedef enum
    {
        wednesday,
        thursday,
        friday
    } workday;
    typedef enum WEEK
    {
        saturday,
        sunday = 0,
        monday,
    } workday;

     

    错误声明二:存在同名的枚举成员


    typedef enum
    {
        wednesday,
        thursday,
        friday
    } workday_1;
    typedef enum WEEK
    {
        wednesday,
        sunday = 0,
        monday,
    } workday_2;

     

     

    3. 使用枚举类型的变量

    3.1 对枚举型的变量赋值。

    实例将枚举类型的赋值与基本数据类型的赋值进行了对比:

    方法一:先声明变量,再对变量赋值


    #include<stdio.h>
    /* 定义枚举类型 */
    enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
    void main()
    {
        /* 使用基本数据类型声明变量,然后对变量赋值 */
        int x, y, z;
        
        x = 10;
        y = 20;
        z = 30;
        
        /* 使用枚举类型声明变量,再对枚举型变量赋值 */
        enum DAY yesterday, today, tomorrow;
        
        yesterday = MON;
        today     = TUE;
        tomorrow  = WED;
        printf("%d %d %d /n", yesterday, today, tomorrow);
    }

     

    方法二:声明变量的同时赋初值


    #include <stdio.h>
    /* 定义枚举类型 */
    enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
    void main()
    {
        /* 使用基本数据类型声明变量同时对变量赋初值 */
        int x=10, y=20, z=30;
        /* 使用枚举类型声明变量同时对枚举型变量赋初值 */
        enum DAY yesterday = MON, 
                            today = TUE,
                       tomorrow = WED;
        printf("%d %d %d /n", yesterday, today, tomorrow);
    }

     

    方法三:定义类型的同时声明变量,然后对变量赋值。


    #include <stdio.h>
    /* 定义枚举类型,同时声明该类型的三个变量,它们都为全局变量 */
    enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today, tomorrow;
    /* 定义三个具有基本数据类型的变量,它们都为全局变量 */
    int x, y, z;
    void main()
    {
        /* 对基本数据类型的变量赋值 */
        x = 10;  y = 20;  z = 30;
        
        /* 对枚举型的变量赋值 */
        yesterday = MON;
        today     = TUE;
        tomorrow  = WED;
        printf("%d %d %d /n", x, y, z); //输出:10 20 30
        printf("%d %d %d /n", yesterday, today, tomorrow); //输出:1 2 3
    }

     

    方法四:类型定义,变量声明,赋初值同时进行。


    #include <stdio.h>
    /* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */
    enum DAY
    {
        MON=1, 
        TUE,
        WED,
        THU,
        FRI,
        SAT,
        SUN 
    }
    yesterday = MON, today = TUE, tomorrow = WED;
    /* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */
    int x = 10, y = 20, z = 30;
    void main()
    {
        printf("%d %d %d /n", x, y, z); //输出:10 20 30
        printf("%d %d %d /n", yesterday, today, tomorrow); //输出:1 2 3
    }

     

    3.2 对枚举型的变量赋整数值时,需要进行类型转换。


    #include <stdio.h>
    enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
    void main()
    {
        enum DAY yesterday, today, tomorrow;
        yesterday = TUE;
        today = (enum DAY) (yesterday + 1); //类型转换
        tomorrow = (enum DAY) 30; //类型转换
        //tomorrow = 3; //错误
        printf("%d %d %d /n", yesterday, today, tomorrow); //输出:2 3 30
    }

     

    3.3 使用枚举型变量


    #include<stdio.h>
    enum

        BELL          = '/a',
        BACKSPACE = '/b',
        HTAB         = '/t',
        RETURN      = '/r',
        NEWLINE    = '/n', 
        VTAB         = '/v',
        SPACE       = ' '
    };
    enum BOOLEAN { FALSE = 0, TRUE } match_flag;
    void main()
    {
        int index = 0;
        int count_of_letter = 0;
        int count_of_space = 0;
        char str[] = "I'm Ely efod";
        match_flag = FALSE;
        for(; str[index] != '/0'; index++)
            if( SPACE != str[index] )
                count_of_letter++;
            else
            {
                match_flag = (enum BOOLEAN) 1;
                count_of_space++;
            }
        
        printf("%s %d times %c", match_flag ? "match" : "not match", count_of_space, NEWLINE);
        printf("count of letters: %d %c%c", count_of_letter, NEWLINE, RETURN);
    }

     

    输出:
    match 2 times
    count of letters: 10
    Press any key to continue

     

    4. 枚举类型与sizeof运算符


    #include <stdio.h>
    enum escapes

        BELL      = '/a',
        BACKSPACE = '/b',
        HTAB      = '/t',
        RETURN    = '/r',
        NEWLINE   = '/n', 
        VTAB      = '/v',
        SPACE     = ' '
    };
    enum BOOLEAN { FALSE = 0, TRUE } match_flag;
    void main()
    {
        printf("%d bytes /n", sizeof(enum escapes)); //4 bytes
        printf("%d bytes /n", sizeof(escapes)); //4 bytes
        printf("%d bytes /n", sizeof(enum BOOLEAN)); //4 bytes
        printf("%d bytes /n", sizeof(BOOLEAN)); //4 bytes
        printf("%d bytes /n", sizeof(match_flag)); //4 bytes
        printf("%d bytes /n", sizeof(SPACE)); //4 bytes
        printf("%d bytes /n", sizeof(NEWLINE)); //4 bytes
        printf("%d bytes /n", sizeof(FALSE)); //4 bytes
        printf("%d bytes /n", sizeof(0)); //4 bytes
    }

     

    5. 综合举例


    #include<stdio.h>
    enum Season
    {
        spring, summer=100, fall=96, winter
    };
    typedef enum
    {
        Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
    }
    Weekday;
    void main()
    {
        /* Season */
        printf("%d /n", spring); // 0
        printf("%d, %c /n", summer, summer); // 100, d
        printf("%d /n", fall+winter); // 193
        Season mySeason=winter;
        if(winter==mySeason)
            printf("mySeason is winter /n"); // mySeason is winter
        
        int x=100;
        if(x==summer)
            printf("x is equal to summer/n"); // x is equal to summer
        printf("%d bytes/n", sizeof(spring)); // 4 bytes
        /* Weekday */
        printf("sizeof Weekday is: %d /n", sizeof(Weekday)); //sizeof Weekday is: 4
        Weekday today = Saturday;
        Weekday tomorrow;
        if(today == Monday)
            tomorrow = Tuesday;
        else
            tomorrow = (Weekday) (today + 1); //remember to convert from int to Weekday
    }

    展开全文
  • Enum使用及原理

    千次阅读 2017-05-20 22:45:36
    首先,直接继承抽象类Enum而不选择使用enum关键字创建枚举类是行不通的,通不过编译:所有enum都继承了java.lang.Enum抽象类,该类的声明为public abstract class Enum<E extends Enum<E>> implements Comparable, ...

    首先,直接继承抽象类Enum而不选择使用enum关键字创建枚举类是行不通的,通不过编译:

    这里写图片描述

    枚举类是实现单例的一个不错选择。

    枚举类构造函数默认为private。

    Enum 一般用来表示一组相同类型的常量。如性别、日期、月份、颜色等。

    枚举类对象在枚举类中以public static final 修饰,但自定义枚举类时,可以添加任意访问修饰符的类变量和实例变量。

    使用enum声明的枚举类默认为final class 因此不能被继承。

    所有enum都继承了java.lang.Enum抽象类,该类的声明为

    public abstract class Enum<E extends Enum<E>>
            implements Comparable<E>, Serializable

    该抽象类中实现的 oridinal、equals、hashCode、clone、compareTo等方法均声明为final,因此自定义的enum不能重写这些方法。

    比如对于clone方法,由于每个枚举对象都是singleton,禁止对枚举对象克隆,因此将clone方法声明为final合情合理。

    下面来看抽象类Enum的compareTo方法

    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }
    
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    getClass()为继承自Object,返回当前对象运行时实际类型对应的Class对象,而getDeclaringClass()为Enum类中的方法,首先获取当前对象的实际class,如果为Enum.class,那么将其返回,如果不是,则返回其超类。
    而compareTo方法比较两个对象时,如果两个对象的实际类型和父类型
    都不相等,就会抛出类型转换异常。这里比较两个对象的实际类型比较好理解,那为什么要比较对象实际类型的超类型呢?

    stackoverflow中给出了答案:

    http://stackoverflow.com/questions/5758660/java-enum-getdeclaringclass-vs-getclass

    Java enum values are permitted to have value-specific class bodies, e.g. (and I hope this syntax is correct...)
    
    public enum MyEnum {
    
       A {
           void doSomething() { ... }
       },
    
    
       B {
           void doSomethingElse() { ... }
       };
    
    }
    
    This will generate inner classes representing the class bodies for A and B. These inner classes will be subclasses of MyEnum.
    
    MyEnum.A.getClass() will return the anonymous class representing A's class body, which may not be what you want.
    
    MyEnum.A.getDeclaringClass(), on the other hand, will return the Class object representing MyEnum.
    
    For simple enums (i.e. ones without constant-specific class bodies), getClass() and getDeclaringClass() return the same thing.

    在我们编写的enum类中,可以声明带body的枚举对象,也就是会生成所谓的匿名类,那么此时该枚举对象的运行时实际类型即为此匿名内部类,而该匿名内部类继承了MyEnum。因此在用compareTo方法比较枚举对象时,不能只靠getClass判断这两个对象类型是否相同。

    在java代码中,我们使用 enum 关键字声明一个枚举类,编译器碰到此关键字时,会进行特殊处理,将该名字的枚举类自动extends java.lang.Enum(这也就是枚举类不能显式继承类的原因,单继承),因此该枚举类便自动继承了来自抽象类Enum的那些实例方法。

    使用 enum 关键字声明一个枚举类还继承了来自抽象类Enum的静态方法(静态方法可以继承而不能重写,只能隐藏)

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }
    
    enumConstantDirectory()为Object类方法
    
    Map<String, T> enumConstantDirectory() {
        if (enumConstantDirectory == null) {
            T[] universe = getEnumConstantsShared();
            if (universe == null)
                throw new IllegalArgumentException(
                    getName() + " is not an enum type");
            Map<String, T> m = new HashMap<>(2 * universe.length);
            for (T constant : universe)
                m.put(((Enum<?>)constant).name(), constant);
            enumConstantDirectory = m;
        }
        return enumConstantDirectory;
    }
    
    T[] getEnumConstantsShared() {
        if (enumConstants == null) {
            if (!isEnum()) return null;
            try {
                final Method values = getMethod("values");
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                                values.setAccessible(true);
                                return null;
                            }
                        });
                @SuppressWarnings("unchecked")
                T[] temporaryConstants = (T[])values.invoke(null);
                enumConstants = temporaryConstants;
            }
            // These can happen when users concoct enum-like classes
            // that don't comply with the enum spec.
            catch (InvocationTargetException | NoSuchMethodException |
                   IllegalAccessException ex) { return null; }
        }
        return enumConstants;
    }

    从上面代码可以看出,valueOf(Class< T > enumType, String name) 方法获取枚举类对象为懒加载,首先判断enumConstantDirectory 这个map是否为空,如果为空则进行第一次初始化加载枚举类对象,构造枚举类对象的工作是通过反射调用真正的枚举类的values()方法(马上谈到)。

    另外,编译器还为新生成的枚举类生成了两个静态方法,重载的valueOf(String name) 和一个values()方法,通过反编译class文件,得到这两个方法的字节码:

    这里写图片描述

    values()方法目前没有看懂,不明白是怎么实现对枚举类构造函数实现懒调用的。但看字节码,每次都拷贝一个新的枚举类对象数组引用。

    valueOf()方法内部调用了抽象类Enum的valueOf()方法,参数为String,根据定义枚举类对象时的字符串名称进行查找。

    枚举类在实际开发中的应用

    由于在数据库表的设计中,经常会有表示状态的字段,值为1、2、3..用来表示不同的状态,比如1代表待付款,2代表待发货,3代表已发货。使用枚举类来作为数据库状态字段值的映射,在数据存入、查询时会使代码变的更加可读。

    在使用mybatis作为数据库持久层时,经常会自定义处理数据库int类型和enum映射关系的typehandler。

    展开全文
  • enum(枚举)

    万次阅读 2019-05-02 18:12:15
    C enum(枚举) 枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。 枚举语法定义格式为: enum 枚举名 {枚举元素1,枚举元素2,……}; 接下来我们举个例子,比如:一星期有 7 天,如果不用枚举,...

    C enum(枚举)

    枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。

    枚举语法定义格式为:

    enum 枚举名 {枚举元素1,枚举元素2,……};

    接下来我们举个例子,比如:一星期有 7 天,如果不用枚举,我们需要使用 #define 来为每个整数定义一个别名:

    #define MON 1 #define TUE 2 #define WED 3 #define THU 4 #define FRI 5 #define SAT 6 #define SUN 7

    这个看起来代码量就比较多,接下来我们看看使用枚举的方式:

    enum DAY
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    };

    这样看起来是不是更简洁了。

    注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。

    可以在定义枚举类型时改变枚举元素的值:

    enum season {spring, summer=3, autumn, winter};

    没有指定值的枚举元素,其值为前一元素加 1。也就说 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5

    枚举变量的定义

    前面我们只是声明了枚举类型,接下来我们看看如何定义枚举变量。

    我们可以通过以下三种方式来定义枚举变量

    1、先定义枚举类型,再定义枚举变量

    enum DAY
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    };
    enum DAY day;

    2、定义枚举类型的同时定义枚举变量

    enum DAY
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    } day;

    3、省略枚举名称,直接定义枚举变量

    enum
    {
          MON=1, TUE, WED, THU, FRI, SAT, SUN
    } day;

    实例

    #include<stdio.h> enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN }; int main() { enum DAY day; day = WED; printf("%d",day); return 0; }

    以上实例输出结果为:

    3

    在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。

    不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。

    以下实例使用 for 来遍历枚举的元素:

    实例

    #include<stdio.h> enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } day; int main() { // 遍历枚举元素 for (day = MON; day <= SUN; day++) { printf("枚举元素:%d \n", day); } }

    以上实例输出结果为:

    枚举元素:1 
    枚举元素:2 
    枚举元素:3 
    枚举元素:4 
    枚举元素:5 
    枚举元素:6 
    枚举元素:7

    以下枚举类型不连续,这种枚举无法遍历。

    enum
    {
        ENUM_0,
        ENUM_10 = 10,
        ENUM_11
    };

    枚举在 switch 中的使用:

    实例

    #include <stdio.h> #include <stdlib.h> int main() { enum color { red=1, green, blue }; enum color favorite_color; /* ask user to choose color */ printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): "); scanf("%d", &favorite_color); /* 输出结果 */ switch (favorite_color) { case red: printf("你喜欢的颜色是红色"); break; case green: printf("你喜欢的颜色是绿色"); break; case blue: printf("你喜欢的颜色是蓝色"); break; default: printf("你没有选择你喜欢的颜色"); } return 0; }

    以上实例输出结果为:

    请输入你喜欢的颜色: (1. red, 2. green, 3. blue): 1
    你喜欢的颜色是红色

    将整数转换为枚举

    以下实例将整数转换为枚举:

    实例

    #include <stdio.h>

    #include <stdlib.h>

    int main()

    {

    enum day

    { saturday,

    sunday,

    monday,

    tuesday,

    wednesday,

    thursday,

    friday } workday;

    int a = 1;

    enum day weekend;

    weekend = ( enum day ) a; //类型转换 //

    weekend = a; //错误

    printf("weekend:%d",weekend);

    return 0; }

     

    1. 用 for 用来遍历枚举元素根本是不可行的,直接上代码:

      #include<stdio.h>
      enum DAY{MON=1, TUE, WED, THU=7, FRI, SAT, SUN};
      
      int main()
      {
              enum DAY day;
              for(day=MON;day<=SUN;day++)
              {
                      printf("day=%d\n",day);
              }
              return 0;
      }

      得到的结果:

      day=1
      day=2
      day=3
      day=4
      day=5
      day=6
      day=7
      day=8
      day=9
      day=10

      所以用来遍历是不可行的,它只是给 day 赋值了一个整数类型的值

    2. 枚举其实可以直接使用,上代码:

      #include <stdio.h>
      #include <stdlib.h>
      
      enum {
       Q,W,E=4,R
      };
      
      int main()
      {
      
         printf("枚举值QWER分别是: %d , %d , %d , %d",Q,W,E,R);
         
         return 0;
      }

      输出:

      枚举值QWER分别是: 0 , 1 , 4 , 5
      fqy

      在 C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。

    3. 不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。

      以下枚举类型不连续,这种枚举无法遍历。

      enum
      {
          ENUM_0,
          ENUM_10 = 10,
          ENUM_11
      };

     

     

     

    展开全文
  • Enum(枚举类)

    万次阅读 多人点赞 2018-04-10 18:35:12
    一、什么情况下使用枚举类? 有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便?二、为什么不用静态常量来替代枚举类呢? public static final int SEASON_SPRING = 1;...

    一、什么情况下使用枚举类?

      有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便?

    二、为什么不用静态常量来替代枚举类呢?

        public static final int SEASON_SPRING = 1;
        public static final int SEASON_SUMMER = 2;
        public static final int SEASON_FALL = 3;
        public static final int SEASON_WINTER = 4;

      枚举类更加直观,类型安全。使用常量会有以下几个缺陷:

      1. 类型不安全。若一个方法中要求传入季节这个参数,用常量的话,形参就是int类型,开发者传入任意类型的int类型值就行,但是如果是枚举类型的话,就只能传入枚举类中包含的对象。

      2. 没有命名空间。开发者要在命名的时候以SEASON_开头,这样另外一个开发者再看这段代码的时候,才知道这四个常量分别代表季节。

    三、枚举类入门

      先看一个简单的枚举类。

    package enumcase;
    
    public enum SeasonEnum {
        SPRING,SUMMER,FALL,WINTER;
    }
    1. enum和class、interface的地位一样
    2. 使用enum定义的枚举类默认继承了java.lang.Enum,而不是继承Object类。枚举类可以实现一个或多个接口。
    3. 枚举类的所有实例都必须放在第一行展示,不需使用new 关键字,不需显式调用构造器。自动添加public static final修饰。
    4. 使用enum定义、非抽象的枚举类默认使用final修饰,不可以被继承。
    5. 枚举类的构造器只能是私有的。

    四、枚举类介绍

      枚举类内也可以定义属性和方法,可是是静态的和非静态的。

    复制代码
    package enumcase;
    
    public enum SeasonEnum {
        SPRING("春天"),SUMMER("夏天"),FALL("秋天"),WINTER("冬天");
        
        private final String name;
        
        private SeasonEnum(String name)
        {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    }
    复制代码

        实际上在第一行写枚举类实例的时候,默认是调用了构造器的,所以此处需要传入参数,因为没有显式申明无参构造器,只能调用有参数的构造器。

      构造器需定义成私有的,这样就不能在别处申明此类的对象了。枚举类通常应该设计成不可变类,它的Field不应该被改变,这样会更安全,而且代码更加简洁。所以我们将Field用private final修饰。

    五、枚举类实现接口

      枚举类可以实现一个或多个接口。与普通类一样,实现接口的时候需要实现接口中定义的所有方法,若没有完全实现,那这个枚举类就是抽象的,只是不需显式加上abstract修饰,系统化会默认加上。

      

    复制代码
    package enumcase;
    
    public enum Operation {
        PLUS{
    
            @Override
            public double eval(double x, double y) {
                return x + y;
            }
            
        },
        MINUS{
    
            @Override
            public double eval(double x, double y) {
                return x - y;
            }
            
        },
        TIMES{
    
            @Override
            public double eval(double x, double y) {
                return x * y;
            }
            
        },
        DIVIDE{
    
            @Override
            public double eval(double x, double y) {
                return x / y;
            }
            
        };
        
        /**
         * 抽象方法,由不同的枚举值提供不同的实现。
         * @param x
         * @param y
         * @return
         */
        public abstract double eval(double x, double y);
        
        public static void main(String[] args) {
            System.out.println(Operation.PLUS.eval(10, 2));
            System.out.println(Operation.MINUS.eval(10, 2));
            System.out.println(Operation.TIMES.eval(10, 2));
            System.out.println(Operation.DIVIDE.eval(10, 2));
        }
    }
    复制代码

      Operatio类实际上是抽象的,不可以创建枚举值,所以此处在申明枚举值的时候,都实现了抽象方法,这其实是匿名内部类的实现,花括号部分是一个类体。我们可以看下编译以后的文件。

      

      共生成了五个class文件,这样就证明了PLUS,MINUS,TIMES,DIVIDE是Operation的匿名内部类的实例。

    六、switch语句里的表达式可以是枚举值

      Java5新增了enum关键字,同时扩展了switch。

    复制代码
    package enumcase;
    
    public class SeasonTest {
        public void judge(SeasonEnum s)
        {
            switch(s)
            {
            case SPRING:
                System.out.println("春天适合踏青。");
                break;
            case SUMMER:
                System.out.println("夏天要去游泳啦。");
                break;
            case FALL:
                System.out.println("秋天一定要去旅游哦。");
                break;
            case WINTER:
                System.out.println("冬天要是下雪就好啦。");
                break;
            }
        }
        
        public static void main(String[] args) {
            SeasonEnum s = SeasonEnum.SPRING;
            SeasonTest test = new SeasonTest();
            test.judge(s);
        }
    }
    复制代码

      case表达式中直接写入枚举值,不需加入枚举类作为限定。




    为什么要引入枚举类

    https://blog.csdn.net/qq_31655965/article/details/55049192

    一个小案例

    你写了一个小程序,不过好久不用了,突然有一天,你想使用一下它。程序要想正确运行,需要将今天星期几存到数据库里。这个时候,你开始犯难了。

    当初的你还很年轻,不懂程序界的险恶,设计这个程序的时候,傻不拉几把这个字段设计为int类型的,用0代表周日,1代表周一。。。6代表周六,添加的时候就setWeekday(0)。但是这么长时间没用了,你忘记自己是从周一开始计算还是周日开始计算了,换句话说,你想不起来0代表的是周一还是周日了!

    于是你各种翻代码,看数据库的字段,数据库保存的信息,终于搞懂了,你很开心,用了一次之后,觉得这个程序没意思,又不用了。

    很久之后,你心血来潮,又想用一次它,很不幸,你又忘记到底0代表周一还是周日了,一番查找之后。你决定重构代码,因为你受不了了!!

    静态变量来帮忙

    经过一番思考,你决定使用七个静态变量来代表星期几,以后只要引用和静态变量就可以了,而不用自己输入012….你这么写:

    public class Weekday {
        public final static int SUN = 0;
        public final static int MON = 1;
        public final static int TUE = 2;
        public final static int WED = 3;
        public final static int THU = 4;
        public final static int FRI = 5;
        public final static int SAT = 6;
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    机智如你,这个时候,只要Weekday.SUN就可以了,不用操心到底应该填写0还是填写1。

    但是这个时候的你,也不是当初初出茅庐的小伙子了,很明显,这样写已经不能满足你了。你还想让这个类做更多的事,比如,你想知道下一天是星期几,还想把今天是星期几打印出来。一番深思熟虑后,你改成了这样:

    public class Weekday {
    
        private Weekday(){}
    
        public final static Weekday SUN = new Weekday();
        public final static Weekday MON = new Weekday();
        public final static Weekday TUE = new Weekday();
        public final static Weekday WED = new Weekday();
        public final static Weekday THU = new Weekday();
        public final static Weekday FRI = new Weekday();
        public final static Weekday SAT = new Weekday();
    
        public static Weekday  getNextDay(Weekday nowDay){
            if(nowDay == SUN) {
                return MON;
            }else if(nowDay == MON) {
                return TUE;
            }else if(nowDay == TUE) {
                return WED;
            }else if(nowDay == WED) {
                return THU;
            }else if(nowDay == THU) {
                return FRI;
            }else if(nowDay == FRI) {
                return SAT;
            }else {
                return SUN;
            }
        }
    
        public static void printNowDay(Weekday nowDay){
            if(nowDay == SUN)
                System.out.println("sunday");
            else if(nowDay == MON)
                System.out.println("monday");
            else if(nowDay == TUE)
                System.out.println("tuesday");
            else if(nowDay == WED)
                System.out.println("wednesday");
            else if(nowDay == THU)
                System.out.println("thursday");
            else if(nowDay == FRI)
                System.out.println("friday");
            else
                System.out.println("saturday");
        }
    
    }
    
    class Test1{
        public static void main(String[] args) {
            Weekday nowday = Weekday.SUN;
            Weekday.printNowDay(nowday);
            Weekday nextDay = Weekday.getNextDay(nowday);
            System.out.print("nextday ====> ");
            Weekday.printNowDay(nextDay);
        }
    }
    //测试结果:
    //sunday
    //nextday ====> monday
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    哟,不错。考虑的很详细。并且私有构造方法后,外界就不能创建该类的对象了,这样就避免了星期八星期九的出现,所有Weekday的对象都在该类内部创建。

    不对,好像缺了点什么,我要的是int!我的int呢?!。所以,你还需要一个这样的方法:

        public static int toInt(Weekday nowDay){
            if(nowDay == SUN)
                return 0;
            else if(nowDay == MON)
                return 1;
            else if(nowDay == TUE)
                return 2;
            else if(nowDay == WED)
                return 3;
            else if(nowDay == THU)
                return 4;
            else if(nowDay == FRI)
                return 5;
            else
               return 6;
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    当你需要一个整形数据的时候,只需要Weekday.toInt(Weekday.SUN);,看起来你好像完成了你的任务。

    但是,你有没有发现,这样写,好麻烦啊。如果想要扩展一下功能,大量的ifelse会让人眼花缭乱。

    有没有更好的方式呢?你大概已经知道了,没错,我们需要枚举类!

    我们先来看看枚举类是什么。

    一个简单的枚举类

    话不多说,先来代码:

    public enum Weekday {
        SUN,MON,TUS,WED,THU,FRI,SAT
    }
    • 1
    • 2
    • 3

    代码这么少?

    没错,这就是枚举类,我们来看看怎么使用它:

    class Test2{
        public static void main(String[] args) {
            Weekday sun = Weekday.SUN;
            System.out.println(sun); // 输出 SUN
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    看起来和上面的静态变量使用方式差不多,而且默认的toString方法返回的就是对应的名字。

    我们上面的那段代码重写toString也是不可以打印出当前是星期几的,因为toString方法没有参数。所以我们自己写了一个printNowDay方法。

    当然,这么简单的枚举类是不可能实现我们的要求的,所以,我们还要接着写:

    public enum Weekday {
        SUN(0),MON(1),TUS(2),WED(3),THU(4),FRI(5),SAT(6);
    
        private int value;
    
        private Weekday(int value){
            this.value = value;
        }
    
        public static Weekday getNextDay(Weekday nowDay){
            int nextDayValue = nowDay.value;
    
            if (++nextDayValue == 7){
                nextDayValue =0;
            }
    
            return getWeekdayByValue(nextDayValue);
        }
    
        public static Weekday getWeekdayByValue(int value) {
            for (Weekday c : Weekday.values()) {
                if (c.value == value) {
                    return c;
                }
            }
            return null;
        }
    }
    
    class Test2{
        public static void main(String[] args) {
            System.out.println("nowday ====> " + Weekday.SAT);
            System.out.println("nowday int ====> " + Weekday.SAT.ordinal());
            System.out.println("nextday ====> " + Weekday.getNextDay(Weekday.SAT)); // 输出 SUN
    
            //输出:
            //nowday ====> SAT
            //nowday int ====> 6
            //nextday ====> SUN
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    这样就完成了我们的目标,和之前的代码比起来,有没有觉得突然高大上了许多?没有那么多烦人的ifelse,世界都清净了。

    好了,现在你大概知道为什么要引入枚举类了吧?就是因为在没有枚举类的时候,我们要定义一个有限的序列,比如星期几,男人女人,春夏秋冬,一般会通过上面那种静态变量的形式,但是使用那样的形式如果需要一些其他的功能,需要些很多奇奇怪怪的代码。所以,枚举类的出现,就是为了简化这种操作。

    可以将枚举类理解为是java的一种语法糖。

    枚举类的用法

    最简单的使用

    最简单的枚举类就像我们上面第一个定义的枚举类一样:

    public enum Weekday {
        SUN,MON,TUS,WED,THU,FRI,SAT
    }
    • 1
    • 2
    • 3

    如何使用它呢?

    先来看看它有哪些方法:

    Weekday方法

    这是Weekday可以调用的方法和参数。发现它有两个方法:value()和valueOf()。还有我们刚刚定义的七个变量。

    枚举变量的方法

    这些事枚举变量的方法。我们接下来会演示几个比较重要的:

    public enum Weekday {
        SUN,MON,TUS,WED,THU,FRI,SAT
    }
    
    class Test3{
        public static void main(String[] args) {
            System.out.println(Weekday.valueOf("mon".toUpperCase()));
            //MON
    
            for (Weekday w : Weekday.values()){
                System.out.println(w + ".ordinal()  ====>" +w.ordinal());
            }
            //SUN.ordinal()  ====>0
            //MON.ordinal()  ====>1
            //TUS.ordinal()  ====>2
            //WED.ordinal()  ====>3
            //THU.ordinal()  ====>4
            //FRI.ordinal()  ====>5
            //SAT.ordinal()  ====>6
    
            System.out.println("Weekday.MON.compareTo(Weekday.FRI) ===> " + Weekday.MON.compareTo(Weekday.FRI));
            System.out.println("Weekday.MON.compareTo(Weekday.MON) ===> " + Weekday.MON.compareTo(Weekday.MON));
            System.out.println("Weekday.MON.compareTo(Weekday.SUM) ===> " + Weekday.MON.compareTo(Weekday.SUN));
            //Weekday.MON.compareTo(Weekday.FRI) ===> -4
            //Weekday.MON.compareTo(Weekday.MON) ===> 0
            //Weekday.MON.compareTo(Weekday.SUM) ===> 1
    
            System.out.println("Weekday.MON.name() ====> " + Weekday.MON.name());
            //Weekday.MON.name() ====> MON
    
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    这段代码,我们演示了几个常用的方法和功能:

    1. Weekday.valueOf() 方法:

      它的作用是传来一个字符串,然后将它转变为对应的枚举变量。前提是你传的字符串和定义枚举变量的字符串一抹一样,区分大小写。如果你传了一个不存在的字符串,那么会抛出异常。

    2. Weekday.values()方法。

      这个方法会返回包括所有枚举变量的数组。在该例中,返回的就是包含了七个星期的Weekday[]。可以方便的用来做循环。

    3. 枚举变量的toString()方法。

      该方法直接返回枚举定义枚举变量的字符串,比如MON就返回【”MON”】。

    4. 枚举变量的.ordinal()方法。

      默认请款下,枚举类会给所有的枚举变量一个默认的次序,该次序从0开始,类似于数组的下标。而.ordinal()方法就是获取这个次序(或者说下标)

    5. 枚举变量的compareTo()方法。

      该方法用来比较两个枚举变量的”大小”,实际上比较的是两个枚举变量的次序,返回两个次序相减后的结果,如果为负数,就证明变量1”小于”变量2 (变量1.compareTo(变量2),返回【变量1.ordinal() - 变量2.ordinal()】)

      compareTo源码

      这是compareTo的源码,会先判断是不是同一个枚举类的变量,然后再返回差值。

    6. 枚举类的name()方法。

      它和toString()方法的返回值一样,事实上,这两个方法本来就是一样的: 
      name方法

      toString方法

      这两个方法的默认实现是一样的,唯一的区别是,你可以重写toString方法。name变量就是枚举变量的字符串形式。 

    还有一些其他的方法我就暂时不介绍了,感兴趣的话可以自己去看看文档或者源码,都挺简单的。

    要点:

    • 使用的是enum关键字而不是class。 

    • 多个枚举变量直接用逗号隔开。 

    • 枚举变量最好大写,多个单词之间使用”_”隔开(比如:INT_SUM)。 

    • 定义完所有的变量后,以分号结束,如果只有枚举变量,而没有自定义变量,分号可以省略(例如上面的代码就忽略了分号)。 

    • 在其他类中使用enum变量的时候,只需要【类名.变量名】就可以了,和使用静态变量一样。

    但是这种简单的使用显然不能体现出枚举的强大,我们来学习一下复杂的使用:

    枚举的高级使用方法

    就像我们前面的案例一样,你需要让每一个星期几对应到一个整数,比如星期天对应0。上面讲到了,枚举类在定义的时候会自动为每个变量添加一个顺序,从0开始。

    假如你希望0代表星期天,1代表周一。。。并且你在定义枚举类的时候,顺序也是这个顺序,那你可以不用定义新的变量,就像这样:

    public enum Weekday {
        SUN,MON,TUS,WED,THU,FRI,SAT
    }
    • 1
    • 2
    • 3

    这个时候,星期天对应的ordinal值就是0,周一对应的就是1,满足你的要求。但是,如果你这么写,那就有问题了:

    public enum Weekday {
        MON,TUS,WED,THU,FRI,SAT,SUN
    }
    • 1
    • 2
    • 3

    我吧SUN放到了最后,但是我还是希0代表SUN,1代表MON怎么办呢?默认的ordinal是指望不上了,因为它只会傻傻的给第一个变量0,给第二个1。。。

    所以,我们需要自己定义变量!

    看代码:

    public enum Weekday {
        MON(1),TUS(2),WED(3),THU(4),FRI(5),SAT(6),SUN(0);
    
        private int value;
    
        private Weekday(int value){
            this.value = value;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们对上面的代码做了一些改变:

    首先,我们在每个枚举变量的后面加上了一个括号,里面是我们希望它代表的数字。

    然后,我们定义了一个int变量,然后通过构造函数初始化这个变量。

    你应该也清楚了,括号里的数字,其实就是我们定义的那个int变量。这句叫做自定义变量。

    请注意:这里有三点需要注意:

    1. 一定要把枚举变量的定义放在第一行,并且以分号结尾。 

    2. 构造函数必须私有化。事实上,private是多余的,你完全没有必要写,因为它默认并强制是private,如果你要写,也只能写private,写public是不能通过编译的。 

    3. 自定义变量与默认的ordinal属性并不冲突,ordinal还是按照它的规则给每个枚举变量按顺序赋值。

    好了,你很聪明,你已经掌握了上面的知识,你想,既然能自定义一个变量,能不能自定义两个呢?

    当然可以:

    public enum Weekday {
        MON(1,"mon"),TUS(2,"tus"),WED(3,"wed"),THU(4,"thu"),FRI(5,"fri"),SAT(6,"sat"),SUN(0,"sun");
    
        private int value;
        private String label;
    
        private Weekday(int value,String label){
            this.value = value;
            this.label = label;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    你可以定义任何你想要的变量。学完了这些,大概枚举类你也应该掌握了,但是,还有没有其他用法呢?

    枚举类中的抽象类

    如果我在枚举类中定义一个抽象方法会怎么样?

    你要知道,枚举类不能继承其他类,也不能被其他类继承。至于为什么,我们后面会说到。

    你应该知道,有抽象方法的类必然是抽象类,抽象类就需要子类继承它然后实现它的抽象方法,但是呢,枚举类不能被继承。。你是不是有点乱?

    我们先来看代码:

    public enum TrafficLamp {
        RED(30) {
            @Override
            public TrafficLamp getNextLamp() {
                return GREEN;
            }
        }, GREEN(45) {
            @Override
            public TrafficLamp getNextLamp() {
                return YELLOW;
            }
        }, YELLOW(5) {
            @Override
            public TrafficLamp getNextLamp() {
                return RED;
            }
        };
    
        private int time;
    
        private TrafficLamp(int time) {
            this.time = time;
        }
    
        //一个抽象方法
        public abstract TrafficLamp getNextLamp();
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    你好像懂了点什么。但是你好像又不太懂。为什么一个变量的后边可以带一个代码块并且实现抽象方法呢?

    别着急,带着这个疑问,我们来看一下枚举类的实现原理。

    枚举类的实现原理

    从最简单的看起:

    public enum Weekday {
        SUN,MON,TUS,WED,THU,FRI,SAT
    }
    • 1
    • 2
    • 3

    还是这段熟悉的代码,我们编译一下它,再反编译一下看看它到底是什么样子的:

    反编译代码

    你是不是觉得很熟悉?反编译出来的代码和我们一开始用静态变量自己写的那个类出奇的相似!

    而且,你看到了熟悉的values()方法和valueOf()方法。

    仔细看,这个类继承了java.lang.Enum类!所以说,枚举类不能再继承其他类了,因为默认已经继承了Enum类。

    并且,这个类是final的!所以它不能被继承!

    回到我们刚才的那个疑问:

    RED(30) {
        @Override
        public TrafficLamp getNextLamp() {
            return GREEN;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    为什么会有这么神奇的代码?现在你差不多懂了。因为RED本身就是一个TrafficLamp对象的引用。实际上,在初始化这个枚举类的时候,你可以理解为执行的是TrafficLamp RED = new TrafficLamp(30) ,但是因为TrafficLamp里面有抽象方法,还记得匿名内部类么?

    我们可以这样来创建一个TrafficLamp引用:

    TrafficLamp RED = new TrafficLamp(30){
        @Override
        public TrafficLamp getNextLamp() {
            return GREEN;
        }
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    而在枚举类中,我们只需要像上面那样写【RED(30){}】就可以了,因为java会自动的去帮我们完成这一系列操作。

    如果你还是不太理解,那么你可以自己去反编译一下TrafficLamp这个类,看看jvm是怎么处理它的就明白了。

    枚举类的其他用法

    说一说枚举类的其他用法。

    switch语句中使用

    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;
            }
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    实现接口

    虽然枚举类不能继承其他类,但是还是可以实现接口的

    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);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    使用接口组织枚举

    public interface Food {
        enum Coffee implements Food {
            BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO
        }
    
        enum Dessert implements Food {
            FRUIT, CAKE, GELATO
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用枚举创建单例模式

    使用枚举创建的单例模式:

    public enum EasySingleton{
        INSTANCE;
    }
    • 1
    • 2
    • 3

    代码就这么简单,你可以使用EasySingleton.INSTANCE调用它,比起你在单例中调用getInstance()方法容易多了。

    我们来看看正常情况下是怎样创建单例模式的:

    用双检索实现单例:

    下面的代码是用双检索实现单例模式的例子,在这里getInstance()方法检查了两次来判断INSTANCE是否为null,这就是为什么叫双检索的原因,记住双检索在java5之前是有问题的,但是java5在内存模型中有了volatile变量之后就没问题了。

    public class DoubleCheckedLockingSingleton{
         private volatile DoubleCheckedLockingSingleton INSTANCE;
    
         private DoubleCheckedLockingSingleton(){}
    
         public DoubleCheckedLockingSingleton getInstance(){
             if(INSTANCE == null){
                synchronized(DoubleCheckedLockingSingleton.class){
                    //double checking Singleton instance
                    if(INSTANCE == null){
                        INSTANCE = new DoubleCheckedLockingSingleton();
                    }
                }
             }
             return INSTANCE;
         }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    你可以访问DoubleCheckedLockingSingleTon.getInstance()来获得实例对象。

    用静态工厂方法实现单例:

    public class Singleton{
        private static final Singleton INSTANCE = new Singleton();
    
        private Singleton(){}
    
        public static Singleton getSingleton(){
            return INSTANCE;
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    你可以调用Singleton.getInstance()方法来获得实例对象。


    上面的两种方式就是懒汉式和恶汉式单利的创建,但是无论哪一种,都不如枚举来的方便。而且传统的单例模式的另外一个问题是一旦你实现了serializable接口,他们就不再是单例的了。但是枚举类的父类【Enum类】实现了Serializable接口,也就是说,所有的枚举类都是可以实现序列化的,这也是一个优点。

    总结

    最后总结一下:

    • 可以创建一个enum类,把它看做一个普通的类。除了它不能继承其他类了。(java是单继承,它已经继承了Enum),可以添加其他方法,覆盖它本身的方法 

    • switch()参数可以使用enum 

    • values()方法是编译器插入到enum定义中的static方法,所以,当你将enum实例向上转型为父类Enum是,values()就不可访问了。解决办法:在Class中有一个getEnumConstants()方法,所以即便Enum接口中没有values()方法,我们仍然可以通过Class对象取得所有的enum实例 

    • 无法从enum继承子类,如果需要扩展enum中的元素,在一个接口的内部,创建实现该接口的枚举,以此将元素进行分组。达到将枚举元素进行分组。 

    • enum允许程序员为eunm实例编写方法。所以可以为每个enum实例赋予各自不同的行为。 

    本文到这里就差不多结束了。可能举得例子不是很恰当,代码写的不是很优雅,不过我只是用来引出枚举的,大家不要鸡蛋里头挑骨头哈哈。

    如果文章内容有什么问题,请及时与我联系。

    除此之外,还有两个枚举集合:【java.util.EnumSet和java.util.EnumMap】没有讲。关于枚举集合的使用会在后面讲集合框架的时候再详细讲解。

    展开全文
  • 深入理解Java枚举类型(enum)

    万次阅读 多人点赞 2018-01-07 11:35:02
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ... 出自【zejian的博客】 关联文章: 深入理解Java类型信息...深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解
  • enum

    千次阅读 2020-02-05 11:10:52
    enum 枚举名{ 枚举值表 } 在枚举值表中应罗列出所有可用值,这些值也称为枚举元素。 枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。 public enum Color { RED, GREEN, BLANK, YELLOW } 这里...
  • enum 详解

    2018-07-09 09:04:52
    enum 简介 jdk版本 1.8.0_102 新建枚举 首先新建一个枚举: package com.aya; public enum Sex { MALE,FEMALE; public void goToilet(){ System.out.pri...
  • C#中Enum用法小结

    千次阅读 2019-06-22 19:14:53
    enums枚举是值类型,数据直接存储在栈中,而不是使用引用和真实数据的隔离方式来存储。 (1)默认情况下,枚举中的第一个变量被赋值为0,...enumTrafficLight { Green, Yellow, Red } enumTraffi...
  • .net 枚举(enum)的使用

    千次阅读 2018-06-20 21:15:34
    1.枚举用参数变量代替数值防止大量使用数值降低可读性和改写难度例:设置用户的权限(用户对应的权限是权限表的值,但是设置用户信息时要默认给用户设置权限但权限的主键又不固定...枚举的定义 public enum RoleiDAt...
  • Java 枚举(enum) 详解7种常见的用法

    万次阅读 多人点赞 2019-07-29 17:10:14
    JDK1.5引入了新的类型——枚举。在Java中它虽然算个“小”功能,却给我的开发带来了“大”方便。 大师兄我【大师兄】又加上自己的理解,来帮助各位理解一下。 用法一:常量 在JDK1.5之前,我们定义常量都是:...
  • C/C++ enum class枚举类型

    万次阅读 2017-11-10 15:40:29
    1. 常见的enum方式 enum A { a0 = 0, a1 = 1 }; enum B { b0 = 0, b1 = 1 }; 2. enum class 方式 enum class CC { cc0 = 0, cc1 = 1 }; enumenum class的区别如下: 1. 使用方式 enum声明的枚举...
  •  一: 在C#中将String转换成Enum:  object Enum.Parse(System.Type enumType, string value, bool ignoreCase); 所以,我们就可以在代码中这么写: enum Colour { Red, Green, Blue }...
  • String 转 Enum 对象关键字 Java

    万次阅读 2016-08-22 10:37:12
    java中 String 字符转成 Enum对象关键字的方法: 使用valueOf转换
  • JAVA项目中enum+switch的用法

    万次阅读 2018-06-28 11:37:53
    昨天遇到的问题,查询相关资料解决如下:Enum类 public enum ServiceTypeEnum { DEPLOYMENT,STATEFULSET } 方法中使用: serviceType = deployment; ServiceTypeEnum typeEnum = ServiceTypeEnum.valueOf(service...
  • java.lang.Enum.valueOf()方法实例

    万次阅读 2014-12-05 14:36:40
    java.lang.Enum.valueOf() 方法返回指定名称enumtype的枚举常量。该名称必须用于声明在此类型的枚举常量的标识符完全匹配。 声明 以下是java.lang.Enum.valueOf()方法的声明 public static T extends EnumT>>
  • enumint enum -> int: int i = enumType.value.ordinal(); int -> enum: enumType b= enumType.values()[i];   enumString enum -> String: enumType.name() String -> enum: enumType.valueOf(name);
  • 成功解决AttributeError: module 'enum' has no attribute 'IntFlag'? 目录 解决问题 解决思路 解决方法 解决问题 AttributeError: module 'enum' has no attribute 'IntFlag'? 解决思路 This is ...
  • java 自定义可继承枚举Enum

    万次阅读 2019-02-25 09:17:35
    1、定义enum抽象类 public class AbstractEnum { private static final Map&lt;String, AbstractEnum&gt; nameEnumMap = new ConcurrentHashMap&lt;&gt;(); @Getter protected String name; ...
  • typedef enumenum详细用法

    万次阅读 多人点赞 2017-08-23 19:40:28
    枚举(enum)通过一种简单的途径,把一串名字与一串整形值联系在一起。可以代替#define声明  枚举一般形式:  enum 可选标签{ 内容.....}可选定义变量定义;  其中“”内容.....”是一些标识符的列表,可能有...
  • iOS: 枚举类型 enum,NS_ENUM,NS_OPTIONS

    万次阅读 2013-08-10 16:33:41
    一般情况下,我们采用C风格的enum关键字可以定义枚举类型。 typedef enum { UIViewAnimationTransitionNone, UIViewAnimationTransitionFlipFromLeft, UIViewAnimationTransitionFlipFromRight, ...
1 2 3 4 5 ... 20
收藏数 392,175
精华内容 156,870
关键字:

enum