java 枚举详解

	枚举
		为什么要使用枚举?枚举就是要某个类型的变量的取值只能为若干个固定值中的一个,否则,编
译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法性,普通变量的方式在并发阶段无法实
现这一目标。
		枚举的概念:枚举实际就是一个类,枚举的成员变量就是枚举类的一个成员对象
		枚举原理
			用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能
				私有的构造方法
				每个元素分别用一个共有的静态成员变量来表示
				可以有共有或抽象方法,例如,提供nextDay方法必须是抽象的
				采用抽象方法定义的nextDay就可将大量的if.else语句转移成一个个独立的类
		枚举的成员变量
			枚举元素必须位于枚举体中最开始部分,枚举元素列表的后要有分号与其他成员分隔。
把枚举中的成员方法或变量等放在枚举元素的前面,编译器报错
		枚举的普通方法
		枚举对象的方法
			toString(),name(),ordinal(),getClass(),
		枚举类的静态方法
			values(),valueOf()
		枚举类的构造方法的规则与应用
			构造方法必须定义成私有的
			如果有多个构造方法,该如何选择哪个构造方法呢?
			枚举元素MON与MON()的效果一样,都是调用默认的构造方法。
		枚举类定义抽象方法:枚举成员如何实现抽象方法(通过一个匿名内部类,与原来的写法不一样
)
		带方法的枚举
			定义枚举TrafficLamp
			实现普通的next方法
			实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采
用类似内部类的方式进行定义
			增加表示时间的构造方法:new Date(300)();
		枚举只有一个成员是,就可以作为一种单例的实现方式
枚举的学习要点如上:


########################################################


枚举详解(由来):

在JDK1.5之前,java可以有两种方式定义新类型:类和接口。对于大部分面向对象编程来说,这两种方法看起来似乎足够了,

但是在一些特殊情况下,这些方法就不适合。例如,想定义一个Color类,它只能有Red 、Green、Blue三种值,其他的任何值

都是非法的,那么JDK1.5之前虽然可以构造这样的代码,但是要做很多的工作,也有可能带来各种不安全的问题。而JDK1.5

之后引入的枚举类型(Enum)就能避免这些问题。

所谓的枚举就是规定好了指定的取值范围,所有的内容只能从指定的范围中取得。


使用简单类完成颜色的固定取值问题。

package com.itmyhome;  

class Color{  
    public static final Color colorRed =  new Color("红色");  
    public static final Color colorGreen =  new Color("蓝色");  
    public static final Color colorBlue =  new Color("绿色");  
    private String name;  
    public Color(String name){  
        this.name = name;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}  
public class T {  
    public static void main(String[] args) throws Exception{  
        Color cRed = Color.colorRed;  
        System.out.println(cRed.getName());  
    }  
}

此时,程序限定了所能取的对象的范围,所以达到了枚举的功能,以上是一种枚举的方式,在最早的java开发中因为没有枚举

这种概念,所以有时候也使用接口表示。

interface Color{  
    public static final int RED = 1;  
    public static final int GREEN = 2;  
    public static final int BLUE = 3;  
}

定义一个枚举类型

在JDK1.5之后,引入了一个新的关键字类型 enum,可以直接定义枚举类型,格式如下:

【public】 enum 枚举类型名称{ 枚举对象1,枚举对象2,.......枚举对象n; }

使用enum关键字定义。

public enum Color {  
    RED,GREEN,BLUE;  
}

因为枚举已经指定好了范围,所以可以使用foreach 进行全部的输出,使用“枚举.values()”的形式取得全部的枚举内容。

package com.itmyhome;  

enum Color {  
    RED,GREEN,BLUE;  
}  

public class T {  
    public static void main(String[] args) throws Exception{  
        for(Color c:Color.values()){  
            System.out.println(c);  
        }  
    }  
}

还可以直接将内容在switch语句上使用。

package com.itmyhome;  

enum Color {  
    RED, GREEN, BLUE;  
}  

public class T {  
    public static void main(String[] args) throws Exception{  
        for(Color c:Color.values()){  
            print(c);  
        }  
    }  
    public static void print(Color color){  
        switch(color){  
            case RED:{  
                System.out.println("红色");  
                break;  
            }  
            case GREEN:{  
                System.out.println("绿色");  
                break;  
            }  
            case BLUE:{  
                System.out.println("蓝色");  
                break;  
            }  
            default:{  
                System.out.println("未知颜色");  
            }  
        }  
    }  
}

Enum

从前面已经清楚的知道,使用enum关键字可以定义一个枚举,实际上此关键字表示的是 java.lang.Enum类型,

即:使用enum声明的枚举类型,就相当于定义一个类,而此类则默认继承java.lang.Enum类。

java.lang.Enum类的定义如下:

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

此类定义的时候使用了泛型机制,而且实现了Comparable接口以及Serializable接口,证明此中类型是可以比较,可以被序列化的。


枚举类的主要方法



Enum类的构造方法:
protected  Enum(String name, int ordinal)
构造方法中接收两个参数,一个表示枚举的名字,一个表示枚举的序号。
for(Color c:Color.values()){  
    System.out.println(c.name()+"----"+c.ordinal());  
}

希望可以使用一些文字表示颜色的信息,则可以按照最早的Color类的形式,在枚举中定义属性及自己的构造方法,

但是一旦定义有参构造之后,在声明枚举对象的时候就必须明确的调用构造方法,并传递参数。

package com.itmyhome;  

enum Color {  
    RED("红色"), GREEN("绿色"), BLUE("蓝色");   //传入参数  
    private String name;  
    private Color(String name){  //定义构造方法  
        this.name = name;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  

}  

public class T {  
    public static void main(String[] args) throws Exception{  
        for(Color c:Color.values()){  
            System.out.println(c.ordinal()+"----"+c.name()+"----"+c.getName());  
        }  
    }  
}

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,

而value则可以是任意类型


########################################################


枚举的七种常用用法:

JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。

用法一:常量

JDK1.5 之前,我们定义常量都是: public static fianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。

public enum Color {  
  RED, GREEN, BLANK, YELLOW  
}  

 

用法二:switch

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

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;  
        }  
    }  
}  

 

用法三:向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 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;  
    }  
    // 普通方法  
    public static String getName(int index) {  
        for (Color c : Color.values()) {  
            if (c.getIndex() == index) {  
                return c.name;  
            }  
        }  
        return null;  
    }  
    // get set 方法  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getIndex() {  
        return index;  
    }  
    public void setIndex(int index) {  
        this.index = index;  
    }  
}  

 

用法四:覆盖枚举的方法

下面给出一个toString()方法覆盖的例子。

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;  
    }  
    //覆盖方法  
    @Override  
    public String toString() {  
        return this.index+"_"+this.name;  
    }  
} 

 

用法五:实现接口

所有的枚举都继承自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);  
    }  
} 

 

用法六:使用接口组织枚举

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

 

用法七:关于枚举集合的使用

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。

关于枚举的实现细节和原理请参考:

参考资料:《ThinkingInJava》第四版


########################################################下面是一篇使用枚举的实例

枚举类型概念

package com.lxq.enumm;  
  
public class EnumDemoOne  
{  
    private enum InnerEnum  
    {  
        RED, GREEN, YELLOW  
    };  
  
    public static void main(String[] args)  
    {  
        System.out.println(InnerEnum.RED);  
        System.out.println(InnerEnum.GREEN);  
        System.out.println(InnerEnum.YELLOW);  
    }  
}  

运行上面的代码,将编辑产生EnumDemoOne.class和EnumDemoOne$InnerEnum.class。

由此说明定义枚举类型其实就是在定义一个类,只不过很多细节由编译器帮你补齐了,所以,某种程度上enum关键词的作用就像是class或interface.当使用enum定义枚举类型时,实际上所定义出来的类型是继承自java.lang.Enum类。而每个被枚举的成员其实就是定义的枚举类型的一个实例,它们都被默认为final。无法改变常数名称所设定的值,它们也是public和static的成员,这与接口中的常量限制相同。可以通过类名称直接使用它们。

Java枚举类型的案例一

package com.lxq.enumm;  
  
public class EnumDemoTwo  
{  
    public enum ColorSelect  
    {  
        red, green, yellow, blue;  
    }  
    public static void main(String[] args)   
    {  
        /* 
        * 枚举类型是一种类型,用于定义变量,以限制变量的赋值 赋值时通过"枚举名.值"来取得相关枚举中的值 
        */  
        ColorSelect m = ColorSelect.blue;  
        switch (m)   
        {  
            /*注意:枚举重写了ToString(),说以枚举变量的值是不带前缀的 
            * 所以为blue而非ColorSelect.blue 
            */  
            case red:  
                System.out.println("color is red");  
                break;  
            case green:  
                System.out.println("color is green");  
                break;  
            case yellow:  
                System.out.println("color is yellow");  
                break;  
            case blue:  
                System.out.println("color is blue");  
                break;  
            }  
            System.out.println("遍历ColorSelect中的值");  
            /*通过values()获得枚举值的数组*/  
            for (ColorSelect c : ColorSelect.values())   
            {  
                System.out.println(c);  
            }  
            System.out.println("枚举ColorSelect中的值有:"+ColorSelect.values().length+"个");  
            /*ordinal()返回枚举值在枚举中的索引位置,从0开始*/  
            System.out.println(ColorSelect.red.ordinal());//0  
            System.out.println(ColorSelect.green.ordinal());//1  
            /*name()返回枚举值在枚举中的索引位置,从0开始*/  
            System.out.println(ColorSelect.yellow.name());//yellow  
            System.out.println(ColorSelect.blue.name());//blue  
            /*枚举默认实现了java.lang.Comparable接口,-1之前,0位置相同,1之后*/   
            System.out.println(ColorSelect.red.compareTo(ColorSelect.green));  
            /*静态valueOf()方法可以让您将指定的字符串尝试转换为枚举类型*/   
            ColorSelect red=ColorSelect.valueOf("red");  
            System.out.println(red.getClass());  
    }  
}  


Java枚举类型的案例二

上面案例一的枚举类型的返回值仅仅是该枚举变量的名称而已,我们当然也可以通过参数自己制定更加友好更加形象的枚举类型的返回值。

下面的代码简单来说,就箱单我们有一个类,类中有构造方法和变量clor,那么我们通过new Light("颜色");就可以新建一个类的实例,其实枚举就是这个意思,

RED ("红色"), GREEN ("绿色"), YELLOW ("黄色");这三个就当然于实例化了三个对象。也就是Light RED=new Light("红色"); Light GREEN=new Light("绿色");
Light YELLOW=new Light("黄色");只不过定义了枚举类型后,剩下的工作由java编译器帮我们完成了。

package com.lxq.enumm;  
  
import java.util.EnumMap;  
import java.util.EnumSet;  
  
public class EnumDemoThree{  
    // 1. 定义枚举类型  
    public enum Light {  
       /*利用构造函数传参利用构造函数传参 
       * 通过括号赋值,而且必须有带参构造器和属性和方法,否则编译出错  
       * 赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值  
       * 如果不赋值则不能写构造器,赋值编译也出错 
       * */    
       RED ("红色"), GREEN ("绿色"), YELLOW ("黄色");  
   
       // 定义私有变量  
       private String clor ;  
   
       // 构造函数,枚举类型只能为私有  
       private Light(String clor) {  
           this.clor = clor;  
       }  
         
       public String getClor(){  
           return this.clor;  
       }  
         
       public void setClor(String clor){  
           this.clor=clor;  
       }  
         
       @Override  
       public String toString() {  
           return this.clor;  
       }  
    }  
   
    /** 
      * @param args 
      */  
    public static void main(String[] args ) {  
       // 1. 遍历枚举类型  
       System.out.println( " 演示枚举类型的遍历 ......" );  
       testTraversalEnum ();  
       // 2. 演示 EnumMap 对象的使用  
       System. out .println( " 演示 EnmuMap 对象的使用和遍历 ....." );  
       testEnumMap ();  
       // 3. 演示 EnmuSet 的使用  
       System. out .println( " 演示 EnmuSet 对象的使用和遍历 ....." );  
       testEnumSet ();  
    }  
   
    /** 
      * 演示枚举类型的遍历 
      */  
    private static void testTraversalEnum() {  
       Light[] allLight = Light.values ();  
       for (Light aLight : allLight) {  
           System. out .println( " 当前灯 name : " + aLight.name());  
           System. out .println( " 当前灯 ordinal : " + aLight.ordinal());  
           System. out .println( " 当前灯: " + aLight);  
       }  
    }  
   
    /** 
      * 演示 EnumMap 的使用, EnumMap 跟 HashMap 的使用差不多,只不过 key 要是枚举类型 
      */  
    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) + "]" );  
       }  
    }  
   
    /** 
      * 演示 EnumSet 如何使用, EnumSet 是一个抽象类,获取一个类型的枚举类型内容 <BR/> 
      * 可以使用 allOf 方法 
      */  
    private static void testEnumSet() {  
       EnumSet<Light> currEnumSet = EnumSet.allOf (Light. class );  
       for (Light aLightSetElement : currEnumSet) {  
           System. out .println( " 当前 EnumSet 中数据为: " + aLightSetElement);  
       }  
    }  
}  


Java枚举类型的案例三

案例三在二的基础上增加了构造时的参数个数,使得这样的枚举有更广泛的用处。

package com.lxq.enumm;  
  
public enum EnumConstant  
{  
    WEEK_00("", "请选择"),WEEK_01("01", "周一"), WEEK_02("02", "周二"), WEEK_03("03", "周三");  
    private String key;  
    private String value;  
    //自定义的构造函数,参数数量,名字随便自己取  
    //构造器默认也只能是private, 从而保证构造函数只能在内部使用   
    private EnumConstant(String key, String value)  
    {  
        this.key = key;  
        this.value = value;  
    }  
  
    public String getKey()  
    {  
        return key;  
    }  
  
    public void setKey(String key)  
    {  
        this.key = key;  
    }  
  
    public String getValue()  
    {  
        return value;  
    }  
  
    public void setValue(String value)  
    {  
        this.value = value;  
    }  
    //重新toString方法,默认的toString方法返回的就是枚举变量的名字,和name()方法返回值一样  
    @Override  
    public String toString()  
    {  
        return this.key+":"+this.value;  
          
    }  
  
}  

package com.lxq.enumm;  
  
public class EnumTest  
{  
  
    /** 
     * @param args 
     */  
    public static void main(String[] args)  
    {  
        EnumConstant[] allday = EnumConstant.values();  
        System.out.println("-----------for begin------------------");  
        for (EnumConstant day : allday)  
        {  
            System.out.println("  name : " + day.name());//枚举变量的名称  
            System.out.println("  ordinal : " + day.ordinal());//枚举变量的序号  
            System.out.println("  : " + day);//就是toString()的返回值  
            System.out.println("  key : " + day.getKey());//取得第一个参数  
            System.out.println("  value : " + day.getValue());//取得第二个参数  
        }  
        System.out.println("-----------for end------------------");  
        System.out.println(EnumConstant.WEEK_00);//就是toString()的返回值  
        System.out.println(EnumConstant.WEEK_01);//就是toString()的返回值  
        System.out.println(EnumConstant.WEEK_02);//就是toString()的返回值  
        System.out.println(EnumConstant.WEEK_03);//就是toString()的返回值       
    }  
  
}  


PS:我常把Light叫做枚举类型,把其中的RED等叫做枚举变量或枚举值。

本以为RED只是一个Light类的一个static final的实例而已。但后然发现不是这样的,所以文中相关表述不正确的已加中划线,

正确的枚举类型原理见下一篇,Java学习整理系列之Java枚举类型的原理http://blog.csdn.net/sup_heaven/article/details/35559117



转载自:http://softbeta.iteye.com/blog/1185573

              http://blog.csdn.net/jiangxinyu/article/details/8239246

      http://blog.csdn.net/sup_heaven/article/details/35295851

http://itmyhome.com/2015/03/java-study-notes-enum/

参考:http://blog.csdn.net/pengkv/article/details/44198081

http://blog.csdn.net/ishallwin/article/details/9440251

枚举方法:http://developer.51cto.com/art/201107/275031.htm

一个完整的例子:http://www.cnblogs.com/linjiqin/archive/2011/02/11/1951632.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值