java中枚举类型的使用

来源:互联网 发布:北京美特软件 编辑:程序博客网 时间:2024/05/22 07:55
枚举类型是javaSE5中新加入的一个元素,它的功能比C++中枚举类型的功能完备的多,下面是一个简单的例子:public enum  Dana {    A,B,C,D}在这里创建了一个名为Dana的枚举类型,它有四个具名值,由于枚举类型的实例是常量,因此按照命名惯例它们都用大写字母表示(有多个单词则用下划线连接)创建了一个枚举类型,那么怎么使用它呢,如下:public static void main(String[] args) {Dana dana = Dana.A;System.out.println(dana);}}这样就可以打印出枚举类型的值了,在创建enum时,编译器会自动添加一些有用的特性,比如,它会创建toString()方法,以便 你可以很方便地显示某个enum实例的名字,上面打印出来的效果也是这个原理,编译器还会创建ordinal()方法,用来表示某个特定enum常量的声明顺序,已经static values()方法,用来在按照enum常量的声明顺序,产生由这些常量值构成的数组:public class EnumOrder { public static void main(String[] args) {  for (Dana dana : Dana.values()) {   System.out.println(dana + ",ordinal " + dana.ordinal());  } }}
打印效果: 尽管enum看起来像是一种新的数据类型,但是这个关键字只是为enum生成对应的类时产生了某些编译器行为,因此在很大程度上可以将enum当作其他任何类来处理,事实上,enum确实是类,并且有自己的方法。可以创建一个enum类,把它看做一个普通的类。除了它不能继承其他类了。(java是单继承,它已经继承了Enum),可以添加其他方法,覆盖它本身的方法 下面我们看看怎么向enum中添加新方法:public enum Dana {A("My name yi A"),B("My name yi B"),C("My name yi C"),D("My name yi D");private String description;private Dana (String description){this.description=description;}public String getDescription(){return description;}public static void main(String[] args) {for(Dana en : Dana.values()){System.out.println(en+": "+en.getDescription());}}}打印效果为: 注意,如果你打算定义自己的方法,那么必须在enum实例序列的最后添加一个分号,同时,java要求你必须先定义enum实例,如果在定义enum实例之前定义了任何方法或属性,那么在编译时就会得到错误信息。在这个例子中,我们的构造器是私有的,但对于它的可访问性而言并没有什么变化,因为即使我们不声明为私有的,我们也只能在enum定义的内部使用其构造器创建enum实例,一旦enum的定义结束,编译器就不允许我们再使用其构造器来创建任何实例了。再看一个覆盖enum的方法的例子:public enum Color {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;}//覆盖方法@Overridepublic String toString() {return this.index+"_"+this.name;}public static void main(String[] args) {for(Color c : values()){System.out.println(c);}}}效果如下: 另外,enum有一个特别实用的特性,就是它可以在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 GREEN : color = Signal.YELLOW;break;case YELLOW : color =Signal.RED;break;}}public String toString() {return "The traffic light is " + color;}public static void main(String[] args) {TrafficLight t =new TrafficLight();for(int i=0;i<7;i++){System.out.println(t);t.change();}}}打印效果为: 由于switch是要在有限的可能值集合中进行选择,因此它与enum正是绝配,请注意enum的名字是如何能够倍加清楚地表明程序意欲何为的。下面我们说一下把静态导入用于enum,先看一个例子:package com.enumDemo;import  static com.enumDemo.Enum.*;public class Test {Enum degree;public Test(Enum degree){this.degree=degree;}public String toString(){return "Test is  "+degree;}    public static void main(String[] args) {System.out.println(new Test(A));System.out.println(new Test(B));System.out.println(new Test(C));}}运行效果为: 使用statica import能够将enum实例的标识符带入当前的命名空间,所以无需再使用enum类型来修饰enum实例。这是一个好办法吗?还是显示地修饰enum实例更好呢?这要看代码得复杂程度了,编译器可以确保你使用的是正确的类型,唯一需要担心的是,使用静态导入会不会使你的代码看起来令人难以理解。在多数情况下,使用静态导入还是有好处的,不过这要具体情况具体分析了。这里要特别注意,在定义enum的同一个文件中,这种技巧无法使用,如果是在默认包中定义enum,这种技巧也无法使用。(在Sun的内部对这一点也是持有不同意见,这里先不去讨论)其实在创建enum时,编译器会为你生成一个相关的类,这个类时继承自java.lang.Enum,这里面有个有意思的问题,enum里面有个values()方法,但这个方法却不属于Enum,这是怎么回事呢,原理,values()是由编译器添加的static方法,可以看出,在创建enum的时候编译器还为其添加了valueOf()方法。由于values()方法是由编译器插入到enum定义中的static方法,所以,如果你将enum实例向上转型为Enum,那么values()方法就不可访问了,不过在Class中有一个getEnumConstants()方法,所以即便Enum接口中没有values()方法,我们仍然可以通过Class对象取得所有enum实例:如:enum Search {HITHER, YOU}public class UpcastEnum {public static void main(String[] args) {//Search[] vals = Search.values();Enum e = Search.HITHER;for (Enum en : e.getClass().getEnumConstants())System.out.println(en);}}效果如下: 
getEnumConstants()是Class上的方法,所以你甚至可以对不是每句的类调用此方法:只不过,此时方法会返回null,所以当你试图使用其返回的结果时会发生异常。如下:public class NonEnum {public static void main(String[] args) {Class<Integer> intClass = Integer.class;try {for (Object en : intClass.getEnumConstants())System.out.println(en);} catch (Exception e) {System.out.println(e);}}}运行效果如下: