java基础---枚举(enum)

来源:互联网 发布:青岛网络电视台爱社区 编辑:程序博客网 时间:2024/06/04 19:24

1、关于java enum

enum 一般用来表示一组相同类型的常量。如性别、日期、月份、颜色等。对这些属性用常量的好处是显而易见的,不仅可以保证单例,且比较时候可以用 ”==” 来替换 equals 。是一种好的习惯。 JDK1.5 之前没有 Enum 这个类型,那时候一般用接口常量来替代。有了 JavaEnum 之后,可以更贴近的表示这种常量。

注:enum--关键字,用来定义枚举,类似class   Enum--java类型


1.1 常量的定义

在JDK1.5 之前,我们定义常量都是: public static fianl.... 。如下,分别用1 表示红灯,3 表示绿灯,2 表示黄灯。

public class Light {    /* 红灯 */    public final static int RED =1;    /* 绿灯 */    public final static int GREEN =3;    /* 黄灯 */    public final static int YELLOW =2;}
枚举类型的简单定义方法如下。比如我们定义红灯、绿灯和黄灯的代码可能如下:
public enum Light {       RED , GREEN , YELLOW ;}

显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类。 而这些类都是类库中Enum类的子类(java.lang.Enum<E>)(编译器为创建的类继承自Enum)。它们继承了这个Enum中的许多有用的方法。

所有枚举值都是public , static , final的,枚举对象里面的值都必须是唯一的。

可以通过Enum类型名直接引用该常量,如Light.RED。


2、enum原理

enum 的语法结构尽管和 class 的语法不一样,但是经过编译器编译之后产生的是一个class文件。该class文件经过反编译可以看到实际上是生成了一个类,该类继承了java.lang.Enum<E>。

枚举类:

public enum Color{      RED,BLUE,BLACK,YELLOW,GREEN  }
编译器将enum类型单独编译成了一个字节码文件:Color.class。

final enum hr.test.Color extends java.lang.Enum {       // 所有的枚举值都是类静态常量   public static final enum hr.test.Color RED;   public static final enum hr.test.Color BLUE;   public static final enum hr.test.Color BLACK;   public static final enum hr.test.Color YELLOW;   public static final enum hr.test.Color GREEN;      private static final synthetic hr.test.Color[] ENUM$VALUES;       // 初始化过程,对枚举类的所有枚举值对象进行第一次初始化   static {        0  new hr.test.Color [1]         3  dup        4  ldc <String "RED"> [16] //把枚举值字符串"RED"压入操作数栈        6  iconst_0  // 把整型值0压入操作数栈        7  invokespecial hr.test.Color(java.lang.String, int) [17] //调用Color类的私有构造器创建      Color对象RED        10  putstatic hr.test.Color.RED : hr.test.Color [21]  //将枚举对象赋给Color的静态常量RED。         .........  枚举对象BLUE等与上同        102  return      };        // 私有构造器,外部不可能动态创建一个枚举类对象(也就是不可能动态创建一个枚举值)。    private Color(java.lang.String arg0, int arg1){       // 调用父类Enum的受保护构造器创建一个枚举对象         invokespecial java.lang.Enum(java.lang.String, int)      };       public static hr.test.Color[] values();         // 实现Enum类的抽象方法      public static hr.test.Color valueOf(java.lang.String arg0);  }  

实际上enum就是一个class,只不过java编译器帮我们做了语法的解析和编译而已。可以把enum看成是一个普通的class,它们都可以定义一些属性和方法

不同之处是:enum不能使用extends关键字继承其他类,因为enum已经继承了java.lang.Enum(java是单一继承)。enum可以实现一个或多个接口

2.1 enum定义的枚举类的特征及其用法

2.2.1、枚举值

Color枚举类就是class,而且是一个不可以被继承的final类。其枚举值(RED,BLUE...)都是Color类型的类静态常量, 我们可以通过下面的方式来得到Color枚举类的一个实例: Color c=Color.RED; 

注意:这些枚举值都是public static final的,也就是我们经常所定义的常量方式,因此枚举类中的枚举值最好全部大写。如果打算在enum类中自己定义方法,那么必须在enum实例序列的最后添加一个分号。同时,java要求你必须先定义enum实例。如果在定义enum实例之前定义了任何方法或属性,那么在编译时就会得到错误信息。

2.2.2、构造方法
即然枚举类是class,当然在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同: 

(1) 构造器只是在构造枚举值的时候被调用。

enum Color{                  RED(255,0,0),BLUE(0,0,255),BLACK(0,0,0),YELLOW(255,255,0),GREEN(0,255,0);                  //构造枚举值,比如RED(255,0,0)                  private Color(int rv,int gv,int bv){                   this.redValue=rv;                   this.greenValue=gv;                   this.blueValue=bv;                  }                    public String toString(){  //覆盖了父类Enum的toString()                  return super.toString()+"("+redValue+","+greenValue+","+blueValue+")";                  }                       private int redValue;  //自定义数据域,private为了封装。                  private int greenValue;                  private int blueValue;   } 
(2) 构造器只能私有private,绝对不允许有public构造器。 这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据域可以允许外部访问。

public static void main(String args[])  {          // Color colors=new Color(100,200,300);  //wrong             Color color=Color.RED;             System.out.println(color);  // 调用了toString()方法  }


2.2.3 枚举方法

所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。 

(1)ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
                 Color.RED.ordinal();  //返回结果:0
                 Color.BLUE.ordinal();  //返回结果:1

(2)compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。(具体可见源代码)
                 Color.RED.compareTo(Color.BLUE);  //返回结果 -1

(3)values()方法: 静态方法,返回一个包含全部枚举值的数组。(注:values方法在Enum中不存在,在enum类中存在的原因是编译器帮忙添加的static方法
                 Color[] colors=Color.values();//遍历枚举
                 for(Color c:colors){
                        System.out.print(c+","); 
                 }//返回结果:RED,BLUE,BLACK YELLOW,GREEN,

(4)toString()方法: 返回枚举常量的名称。
                 Color c=Color.RED;
                 System.out.println(c);//返回结果: RED

(5)valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
                 Color.valueOf("BLUE");   //返回结果: Color.BLUE

(6)equals()方法:比较两个枚举类对象的引用。


3、switch中使用enum 

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

Color color=Color.RED;  switch(color){          case RED: System.out.println("it's red");break;          case BLUE: System.out.println("it's blue");break;          case BLACK: System.out.println("it's blue");break;  } 

4、给enum自定义属性和方法

public enum Light {       // 利用构造函数传参       RED (1), GREEN (3), YELLOW (2) , ORANGE(4){        @Override        public boolean isRest() {            return true;        }       };        // 定义私有变量       private int nCode ;        // 构造函数,枚举类型只能为私有       private Light( int _nCode) {           this . nCode = _nCode;       }        @Override//覆盖方法       public String toString() {           return String.valueOf ( this . nCode );       }       public boolean isRest() {        return false;        }    }

5、EnumSet,EnumMap 的应用

enum要求其成员都是唯一的,所以enum看起来也具有集合的行为。不过,由于不能从enum中删除或添加元素,所以它只能算是不太有用的集合。

    /**      * 演示 EnumMap 的使用, EnumMap 跟 HashMap 的使用差不多,只不过 key 要是枚举类型,value为任意类型      */    private static void testEnumMap() {       // 1. 演示定义 EnumMap 对象, EnumMap 对象的构造函数需要参数传入 , 默认是 key 的类的类型       EnumMap<Light, String> currEnumMap = new EnumMap<Light, String>(              Light. class );       currEnumMap.put(Light. RED , " 红灯 " );       currEnumMap.put(Light. GREEN , " 绿灯 " );       currEnumMap.put(Light. YELLOW , " 黄灯 " );        // 2. 遍历对象       for (Light aLight : Light.values ()) {           System. out .println( "[key=" + aLight.name() + ",value="                  + currEnumMap.get(aLight) + "]" );       }    }输出结果:演示 EnmuMap 对象的使用和遍历 .....[key=RED,value= 红灯 ][key=GREEN,value= 绿灯 ][key=YELLOW,value= 黄灯 ]

   /**      * 演示 EnumSet 如何使用, EnumSet 是一个抽象类,获取一个类型的枚举类型内容       * 可以使用 allOf 方法      */    private static void testEnumSet() {       EnumSet<Light> currEnumSet = EnumSet.allOf (Light. class );       for (Light aLightSetElement : currEnumSet) {           System. out .println( " 当前 EnumSet 中数据为: " + aLightSetElement);       }     }}输出结果:演示 EnmuSet 对象的使用和遍历 .....当前 EnumSet 中数据为: 1当前 EnumSet 中数据为: 3当前 EnumSet 中数据为: 2

6、总结

1.    代码:
public class State {
public static final int ON = 1;
public static final Int OFF= 0;
}
 
有什么不好了,大家都这样用了很长时间了,没什么问题啊。
首先,它不是类型安全的。你必须确保是int
其次,你还要确保它的范围是0 和1
最后,很多时候你打印出来的时候,你只看到 1 和0 ,
 
但其没有看到代码的人并不知道你的企图,抛弃你所有旧的public static final 常量吧
 
2.    可以创建一个enum 类,把它看做一个普通的类。除了它不能继承其他类了。(java 是单继承,它已经继承了Enum),
可以添加其他方法,覆盖它本身的方法


3.    switch() 参数可以使用enum 了
 
4.    values() 方法是编译器插入到enum 定义中的static 方法,所以,当你将enum 实例向上转型为父类Enum 是,values() 就不可访问了。解决办法:在Class 中有一个getEnumConstants() 方法,所以即便Enum 接口中没有values() 方法,我们仍然可以通过Class 对象取得所有的enum 实例
 
5.    无法从enum 继承子类,如果需要扩展enum 中的元素,在一个接口的内部,创建实现该接口的枚举,以此将元素进行分组。达到将枚举元素进行分组。
 
6.    使用EnumSet 代替标志。enum 要求其成员都是唯一的,但是enum 中不能删除添加元素。
 
7.    EnumMap 的key 是enum ,value 是任何其他Object 对象。
 
8.    enum 允许程序员为eunm 实例编写方法。所以可以为每个enum 实例赋予各自不同的行为。
 
9.    使用enum 的职责链(Chain of Responsibility) . 这个关系到设计模式的职责链模式。以多种不同的方法来解决一个问题。然后将他们链接在一起。当一个请求到来时,遍历这个链,直到链中的某个解决方案能够处理该请求。
 
10.   使用enum 的状态机
 
11.   使用enum 多路分发


参考来源:

Java中的Enum的使用与分析

Java Enum 学习

java enum(枚举)使用详解 + 总结

java枚举类型enum的使用


0 0
原创粉丝点击