java 枚举

C 语言中可以这样来定义枚举

 

[cpp] view plain copy
 
 print?
  1. enum color {  
  2.         RED=0, GREEN, BLUE, YELLOW  
  3. } col;  


关键字 enum 定义枚举,在定义枚举的同时,声明该枚举变量 col.

 

 

注意:C 语言中枚举成员的值是根据上下文自动加 1 的(GREEN = 1, BLUE = 2 等)。

 

C 语言中 switch 语句支持枚举类型

 

[cpp] view plain copy
 
 print?
  1. #include<stdio.h>  
  2. int main() {  
  3.     enum color {  
  4.         RED=0, GREEN, BLUE, YELLOW  
  5.     } col;  
  6.   
  7.     int cl;  
  8.   
  9.     printf("0=red,1=green,2=blue,3=yellow. seclect:\n");  
  10.     scanf("%d",&cl);  
  11.   
  12.     col=(enum color) cl;  
  13.   
  14.     switch(col) {  
  15.         case RED:  
  16.             printf("the color is red\n");  
  17.             break;  
  18.         case GREEN:  
  19.             printf("the color is green\n");  
  20.             break;  
  21.         case BLUE:  
  22.              printf("the color is blue\n");  
  23.             break;  
  24.         case YELLOW:  
  25.             printf("the color is yellow\n");  
  26.             break;  
  27.         defalut:  
  28.             printf("no this color\n");  
  29.             break;  
  30.     }  
  31.   
  32.     return 0;  
  33. }  


那么,Java 里面的枚举与其类似,但是又不是完全一样。

 

 

Java 语言中定义枚举也是使用关键字 enum

 

[java] view plain copy
 
 print?
  1. public enum Color {  
  2.     RED, GREEN, BLUE, YELLOW;  
  3. }  

 

 

上述定义了一个枚举类型 Color(可以说是类,编译之后是 Color.class).

 

上面的定义,还可以改成下面的这种形式

 

[java] view plain copy
 
 print?
  1. public enum Color {  
  2.     RED(), GREEN(), BLUE(), YELLOW();  
  3. }  


到这里你就会觉得迷茫(如果你是初学者的话),为什么这样子也可以?

 

 

其实,枚举的成员就是枚举对象,只不过他们是静态常量而已。

 

使用 javap 命令(javap 文件名<没有后缀.class>)可以反编译 class 文件,如下:

 

我们可以使用普通类来模拟枚举,下面定义一个 Color 类。

 

[java] view plain copy
 
 print?
  1. public class Color {  
  2.     private static final Color RED = new Color();  
  3.     private static final Color GREEN = new Color();  
  4.     private static final Color BLUE = new Color();  
  5.     private static final Color YELLOW = new Color();  
  6. }  


对比一下,你就明白了。

 

 

如果按照这个逻辑,是否还可以为其添加另外的构造方法?答案是肯定的!

 

[html] view plain copy
 
 print?
  1. public enum Color {  
  2.         RED("red color", 0), GREEN("green color", 1),   
  3.         BLUE("blue color", 2), YELLOW("yellow color", 3);  
  4.   
  5.         Color(String name, int id) {  
  6.             _name = name;  
  7.             _id = id;  
  8.         }  
  9.   
  10.         String _name;  
  11.         int _id;  
  12. }  

 

为 Color 声明了两个成员变量,并为其构造带参数的构造器。

如果你这样创建一个枚举

 

[java] view plain copy
 
 print?
  1. public enum Color {  
  2.         RED("red color", 0), GREEN("green color", 1),   
  3.         BLUE("blue color", 2), YELLOW("yellow color", 3);  
  4. }  


编译器就会报错

 

 

[html] view plain copy
 
 print?
  1. The constructor EnumDemo.Color(String, int) is undefined  

 

 

到此,你就可以明白,枚举和普通类基本一致(但是不完全一样)。

 

对于类来讲,最好将其成员变量私有化,然后,为成员变量提供 get、set 方法。

按照这个原则,可以进一步写好 enum Color.

 

[java] view plain copy
 
 print?
  1. public enum Color {  
  2.         RED("red color", 0), GREEN("green color", 1),  
  3.         BLUE("blue color", 2), YELLOW("yellow color", 3);  
  4.   
  5.         Color(String name, int id) {  
  6.             _name = name;  
  7.             _id = id;  
  8.         }  
  9.   
  10.         private String _name;  
  11.         private int _id;  
  12.           
  13.         public void setName(String name) {  
  14.             _name = name;  
  15.         }  
  16.           
  17.         public void setId(int id) {  
  18.             _id = id;  
  19.         }  
  20.   
  21.         public String getName() {  
  22.             return _name;  
  23.         }  
  24.   
  25.         public int getId() {  
  26.             return _id;  
  27.         }  
  28. }  

 

 

但是,java 设计 enum 的目的是提供一组常量,方便用户设计。

如果我们冒然的提供 set 方法(外界可以改变其成员属性),好像是有点违背了设计的初衷。

那么,我们应该舍弃 set 方法,保留 get 方法。

 

[java] view plain copy
 
 print?
  1. public enum Color {  
  2.         RED("red color", 0), GREEN("green color", 1),  
  3.         BLUE("blue color", 2), YELLOW("yellow color", 3);  
  4.   
  5.         Color(String name, int id) {  
  6.             _name = name;  
  7.             _id = id;  
  8.         }  
  9.   
  10.         private String _name;  
  11.         private int _id;  
  12.           
  13.         public String getName() {  
  14.             return _name;  
  15.         }  
  16.   
  17.         public int getId() {  
  18.             return _id;  
  19.         }  
  20. }  


普通类,我们可以将其实例化,那么,能否实例化枚举呢?

 

 

在回答这个问题之前,先来看看,编译之后的 Color.class 文件

 

[java] view plain copy
 
 print?
  1. public static enum Color {  
  2.         RED("red color", 0), GREEN("green color", 1),  
  3.         BLUE("blue color", 2), YELLOW("yellow color", 3);  
  4.   
  5.         private String _name;  
  6.         private int _id;  
  7.   
  8.         private Color(String name, int id) {  
  9.             this._name = name;  
  10.             this._id = id;  
  11.         }  
  12.   
  13.         public String getName() {  
  14.             return this._name;  
  15.         }  
  16.   
  17.         public int getId() {  
  18.             return this._id;  
  19.         }  
  20. }  


可以看出,编译器淘气的为其构造方法加上了 private,那么也就是说,我们无法实例化枚举。

 

 

所有枚举类都继承了 Enum 类的方法,包括 toString 、equals、hashcode 等方法。

因为 equals、hashcode 方法是 final 的,所以不可以被枚举重写(只可以继承)。

但是,可以重写 toString 方法。

 

关于 Enum 源码,详见附录!

 

那么,使用 Java 的不同类来模拟一下枚举,大概是这个样子

 

[java] view plain copy
 
 print?
  1. package mark.demo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class Color {  
  7.     private static final Color RED = new Color("red color", 0);  
  8.     private static final Color GREEN = new Color("green color", 1);  
  9.     private static final Color BLUE = new Color("blue color", 2);  
  10.     private static final Color YELLOW = new Color("yellow color", 3);  
  11.   
  12.     private final String _name;  
  13.     private final int _id;  
  14.   
  15.     private Color(String name, int id) {  
  16.         _name = name;  
  17.         _id = id;  
  18.     }  
  19.   
  20.     public String getName() {  
  21.         return _name;  
  22.     }  
  23.   
  24.     public int getId() {  
  25.         return _id;  
  26.     }  
  27.   
  28.     public static List<Color> values() {  
  29.         List<Color> list = new ArrayList<Color>();  
  30.         list.add(RED);  
  31.         list.add(GREEN);  
  32.         list.add(BLUE);  
  33.         list.add(YELLOW);  
  34.         return list;  
  35.     }  
  36.   
  37.     @Override  
  38.     public String toString() {  
  39.         return "the color _name=" + _name + ", _id=" + _id;  
  40.     }  
  41.   
  42. }  



 

附录

 

Enum.java

 

[java] view plain copy
 
 print?
    1. /* 
    2.  * %W% %E% 
    3.  * 
    4.  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 
    5.  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 
    6.  */  
    7.   
    8. package java.lang;  
    9.   
    10. import java.io.Serializable;  
    11. import java.io.IOException;  
    12. import java.io.InvalidObjectException;  
    13. import java.io.ObjectInputStream;  
    14. import java.io.ObjectStreamException;  
    15.   
    16. /** 
    17.  * This is the common base class of all Java language enumeration types. 
    18.  * 
    19.  * @author  Josh Bloch 
    20.  * @author  Neal Gafter 
    21.  * @version %I%, %G% 
    22.  * @since   1.5 
    23.  */  
    24. public abstract class Enum<E extends Enum<E>>  
    25.         implements Comparable<E>, Serializable {  
    26.     /** 
    27.      * The name of this enum constant, as declared in the enum declaration. 
    28.      * Most programmers should use the {@link #toString} method rather than 
    29.      * accessing this field. 
    30.      */  
    31.     private final String name;  
    32.   
    33.     /** 
    34.      * Returns the name of this enum constant, exactly as declared in its 
    35.      * enum declaration. 
    36.      *  
    37.      * <b>Most programmers should use the {@link #toString} method in 
    38.      * preference to this one, as the toString method may return 
    39.      * a more user-friendly name.</b>  This method is designed primarily for 
    40.      * use in specialized situations where correctness depends on getting the 
    41.      * exact name, which will not vary from release to release. 
    42.      * 
    43.      * @return the name of this enum constant 
    44.      */  
    45.     public final String name() {  
    46.     return name;  
    47.     }  
    48.   
    49.     /** 
    50.      * The ordinal of this enumeration constant (its position 
    51.      * in the enum declaration, where the initial constant is assigned 
    52.      * an ordinal of zero). 
    53.      *  
    54.      * Most programmers will have no use for this field.  It is designed 
    55.      * for use by sophisticated enum-based data structures, such as 
    56.      * {@link java.util.EnumSet} and {@link java.util.EnumMap}. 
    57.      */  
    58.     private final int ordinal;  
    59.   
    60.     /** 
    61.      * Returns the ordinal of this enumeration constant (its position 
    62.      * in its enum declaration, where the initial constant is assigned 
    63.      * an ordinal of zero). 
    64.      *  
    65.      * Most programmers will have no use for this method.  It is 
    66.      * designed for use by sophisticated enum-based data structures, such 
    67.      * as {@link java.util.EnumSet} and {@link java.util.EnumMap}. 
    68.      * 
    69.      * @return the ordinal of this enumeration constant 
    70.      */  
    71.     public final int ordinal() {  
    72.     return ordinal;  
    73.     }  
    74.   
    75.     /** 
    76.      * Sole constructor.  Programmers cannot invoke this constructor. 
    77.      * It is for use by code emitted by the compiler in response to 
    78.      * enum type declarations. 
    79.      * 
    80.      * @param name - The name of this enum constant, which is the identifier 
    81.      *               used to declare it. 
    82.      * @param ordinal - The ordinal of this enumeration constant (its position 
    83.      *         in the enum declaration, where the initial constant is assigned 
    84.      *         an ordinal of zero). 
    85.      */  
    86.     protected Enum(String name, int ordinal) {  
    87.     this.name = name;  
    88.     this.ordinal = ordinal;  
    89.     }  
    90.   
    91.     /** 
    92.      * Returns the name of this enum constant, as contained in the 
    93.      * declaration.  This method may be overridden, though it typically 
    94.      * isn't necessary or desirable.  An enum type should override this 
    95.      * method when a more "programmer-friendly" string form exists. 
    96.      * 
    97.      * @return the name of this enum constant 
    98.      */  
    99.     public String toString() {  
    100.     return name;  
    101.     }  
    102.   
    103.     /** 
    104.      * Returns true if the specified object is equal to this 
    105.      * enum constant. 
    106.      * 
    107.      * @param other the object to be compared for equality with this object. 
    108.      * @return  true if the specified object is equal to this 
    109.      *          enum constant. 
    110.      */  
    111.     public final boolean equals(Object other) {   
    112.         return this==other;  
    113.     }  
    114.   
    115.     /** 
    116.      * Returns a hash code for this enum constant. 
    117.      * 
    118.      * @return a hash code for this enum constant. 
    119.      */  
    120.     public final int hashCode() {  
    121.         return super.hashCode();  
    122.     }  
    123.   
    124.     /** 
    125.      * Throws CloneNotSupportedException.  This guarantees that enums 
    126.      * are never cloned, which is necessary to preserve their "singleton" 
    127.      * status. 
    128.      * 
    129.      * @return (never returns) 
    130.      */  
    131.     protected final Object clone() throws CloneNotSupportedException {  
    132.     throw new CloneNotSupportedException();  
    133.     }  
    134.   
    135.     /** 
    136.      * Compares this enum with the specified object for order.  Returns a 
    137.      * negative integer, zero, or a positive integer as this object is less 
    138.      * than, equal to, or greater than the specified object. 
    139.      *  
    140.      * Enum constants are only comparable to other enum constants of the 
    141.      * same enum type.  The natural order implemented by this 
    142.      * method is the order in which the constants are declared. 
    143.      */  
    144.     public final int compareTo(E o) {  
    145.     Enum other = (Enum)o;  
    146.     Enum self = this;  
    147.     if (self.getClass() != other.getClass() && // optimization  
    148.             self.getDeclaringClass() != other.getDeclaringClass())  
    149.         throw new ClassCastException();  
    150.     return self.ordinal - other.ordinal;  
    151.     }  
    152.   
    153.     /** 
    154.      * Returns the Class object corresponding to this enum constant's 
    155.      * enum type.  Two enum constants e1 and  e2 are of the 
    156.      * same enum type if and only if 
    157.      *   e1.getDeclaringClass() == e2.getDeclaringClass(). 
    158.      * (The value returned by this method may differ from the one returned 
    159.      * by the {@link Object#getClass} method for enum constants with 
    160.      * constant-specific class bodies.) 
    161.      * 
    162.      * @return the Class object corresponding to this enum constant's 
    163.      *     enum type 
    164.      */  
    165.     public final Class<E> getDeclaringClass() {  
    166.     Class clazz = getClass();  
    167.     Class zuper = clazz.getSuperclass();  
    168.     return (zuper == Enum.class) ? clazz : zuper;  
    169.     }  
    170.   
    171.     /** 
    172.      * Returns the enum constant of the specified enum type with the 
    173.      * specified name.  The name must match exactly an identifier used 
    174.      * to declare an enum constant in this type.  (Extraneous whitespace 
    175.      * characters are not permitted.)  
    176.      * 
    177.      * @param enumType the <tt>Class</tt> object of the enum type from which 
    178.      *      to return a constant 
    179.      * @param name the name of the constant to return 
    180.      * @return the enum constant of the specified enum type with the 
    181.      *      specified name 
    182.      * @throws IllegalArgumentException if the specified enum type has 
    183.      *         no constant with the specified name, or the specified 
    184.      *         class object does not represent an enum type 
    185.      * @throws NullPointerException if <tt>enumType</tt> or <tt>name</tt> 
    186.      *         is null 
    187.      * @since 1.5 
    188.      */  
    189.     public static <T extends Enum<T>> T valueOf(Class<T> enumType,  
    190.                                                 String name) {  
    191.         T result = enumType.enumConstantDirectory().get(name);  
    192.         if (result != null)  
    193.             return result;  
    194.         if (name == null)  
    195.             throw new NullPointerException("Name is null");  
    196.         throw new IllegalArgumentException(  
    197.             "No enum const " + enumType +"." + name);  
    198.     }  
    199.   
    200.     /** 
    201.       * prevent default deserialization 
    202.       */  
    203.     private void readObject(ObjectInputStream in) throws IOException,  
    204.         ClassNotFoundException {  
    205.             throw new InvalidObjectException("can't deserialize enum");  
    206.     }  
    207.   
    208.     private void readObjectNoData() throws ObjectStreamException {  
    209.         throw new InvalidObjectException("can't deserialize enum");  
    210.     }  
    211.   
    212.     /** 
    213.      * enum classes cannot have finalize methods. 
    214.      */  
    215.     protected final void finalize() { }  
    216. }  
posted @ 2017-07-21 08:42  babyyage  阅读(170)  评论(0编辑  收藏  举报