参考:java技术手册

 

java有两种特殊形式的类型,在java类型系统中扮演着特定的角色。这两种类型是枚举类 型(enumerated type)和注解类型(annotation type)。

 

本文介绍枚举。

 

一、枚举的定义
枚举是类的变种。

假设我们要定义红、黄、蓝色中颜色的枚举,我们可以使用enum关键字定义这个类型:

public enum PrimaryColor {
// 实例列表末尾的分号是可选的
  RED, GREEN, BLUE
}

注意:
(1)如上PrimaryColor定义的是一个类型,这个类型是枚举。

(2)枚举内部的REG、GREEN、BLUE实际上是PrimaryColer类型的实例

 

通过如下包含成员的枚举类型定义,更好的理解枚举实例的概念:

特殊的类,所以可以拥有成员(字段和方法)。

  假设,我们要定义一个枚举,包含前几个正多边形(等边等角的形状),而且想为这些形状指定一些属性(在方法中指定)。我们可以使用接收一个参数的枚举实现这个需求,如下所示:

public enum RegularPolygon {
      // 有参数的枚举必须使用分号。由于这些实际上是RegularPolygon的实例,所以可以传入 “构造方法” 参数。
      TRIANGLE(3), SQUARE(4), PENTAGON(5), HEXAGON(6); 

      private Shape shape; 

      public Shape getShape() {
           return shape;
      } 

      private RegularPolygon(int sides) {
           switch (sides) {
               case 3:
                   // 假设这些形状的构造方法接收的参数是边长和角度
                   shape = new Triangle(1,1,1,60,60,60);
                   break;
               case 4:
                   shape = new Rectangle(1,1);
                   break;
               case 5:
                   shape = new Pentagon(1,1,1,1,1,108,108,108,108,108);
                   break;
               case 6:
                   shape = new Hexagon(1,1,1,1,1,1,120,120,120,120,120,120);
                   break;
             }
         }
    }

  注意,如上:

  (1)如果字段或方法有主体,那么实例列表后面必须加上分号。 

  (2)如上样例中,枚举实例(TRIANGLE、SQUARE、PENTAGON、HEXAGON)具有参数,所以要显式提供构造函数。枚举实例由Java运行时创建,在创建TRIANGLE、SQUARE、PENTAGON、HEXAGON实例时,调用RegularPlygon ()构造方法,分别传入2、4、5、6入参,为这几个枚举实例分配内存空间和赋值。本质上每个枚举实例包含一个shape字段和2个方法。

把构造方法声明为私有方法

  (4)枚举有如下特殊性:

    • 都(隐式)扩展 java.lang.Enum 类;(所以不可继承其他类)

    • 不能泛型化;

    • 可以实现接口;

不能被扩展子类;

    • 只能有一个私有(或使用默认访问权限)的构造方法

    • 所有的枚举值默认都是 public static final 的。

 

二、枚举引入的版本

enum类型是java1.5引入的。

  

三、枚举类型的使用

(1)类似常量的方式使用

  支持枚举之前,常量只能通过public static fianl方式定义。

       引入枚举后,可以使用枚举实现类似常量方式的代码使用。如:

public enum PrimaryColor {
    // 实例列表末尾的分号是可选的
    RED, GREEN, BLUE
  }       PrimaryColor类型的REG、GREEN、BLUE实例可以按照静态字段的方式引用:PrimaryColor.RED、PrimaryColor. GREEN 和 PrimaryColor.BLUE。

(2)配合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;  
              }  
        }  
  }

 

 

(3)配合for循环遍历枚举中的实例

private enum SimpleEnum { 
            SPRING, SUMMER, AUTUMN, WINTER  
      }   public class EnumTest { 
		    /** 
		    * 循环枚举,输出ordinal属性;若枚举有内部属性,则也输出。(说的就是我定义的TYPE类型的枚举的typeName属性) 
		    */  
		    private static void forEnum() {  
SimpleEnum simpleEnum : SimpleEnum.values()) {  
				        System.out.println(simpleEnum + "  ordinal  " + simpleEnum.ordinal());  
			      }  
		    }	
	  }

  打印结果是:

  SPRING ordinal 0

  SUMMER ordinal 1

  AUTUMN ordinal 3

  WINTER ordinal 4

       注:

      (1)如上ordinal是继承自 java.lang.Enum 类的int类型字段

      (2)如上println打印中simpleEnum参数会自动调用java.lang.Enum类型从Object中继承的toString()方法转换。

      (3)Java编译器自动在enum类型中插入一些方法,其中就包括values()。所以在enum类型中并没有实现values()方式,程序在没编译的时候,自然就没法查看values()方法的源码。

 

(4)枚举中自定义方法、和覆盖继承自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;  
		    } 		    // 普通方法  
		    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;  
		    } 
     @Override  
    public String toString() { 
      returnthis.index+"_"+this.name;  
    }  
	  }
  public class EnumTest { 
      ......
	    private static void forEnum() {  
		      for (Color color : Color.values()) {  
			        System.out.println("color = " + color + "    color.name = " + color.getName() + "   color.index = " + color.getIndex());  
		      }  
	    }  
	    ......
  }

 

(5)枚举实例的比较

 枚举本质上是类型,枚举实例本质上是对象。所以枚举类型对象之间的比较也采用equals方法。但是呢,同class类型对象的不同是,==在class类型的比较中实际上比较的是两个引用是否指向同一对象;==在做枚举类型对象比较时,是比较对象的值是否相等,可替代equals()方法

 

(6)枚举可以通过implements关键字继承接口

      使用方式同class继承接口。

 

(7)枚举集合

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