第十四章、枚举类
、枚举类型简介
在JDK1.5之前,JAVA可以有两种方式定义新类型:类和接口。对于大部分面向对象编程来说,这两种方法看起来似乎足够了,但是在一些特殊情况下,这些方法就不适合。例如,想定义一个Color类,它只能有Red、Green、Blue三种值,其他的任何值都是非法的,那么JDK1.5之前虽然可以构造这样的代码,但是要做很多的工作,也有可能带来各种不安全的问题。而JDK1.5之后引入的枚举类型(Enum)就能避免这些问题。
所谓的枚举就是规定好了指定的取值范围,所有的内容只能从指定的范围中取得。
使用简单类完成颜色的固定取值问题:
·此时,一个类只能产生固定的几个对象。
class Color{ public static final Color RED = new Color("红色") ; // 定义第一个对象 public static final Color GREEN = new Color("绿色") ; // 定义第一个对象 public static final Color BLUE = new Color("蓝色") ; // 定义第一个对象 private String name ; private Color(String name){ this.name = name ; } public void setName(String name){ this.name = name ; } public String getName(){ return this.name ; } public static Color getInstance(int i){ switch(i){ case 1:{ return RED ; } case 2:{ return GREEN ; } case 3:{ return BLUE ; }default:{ return null ; } } } }; public class ColorDemo01{ public static void main(String args[]){ Color c1 = Color.RED ; // 取得红色 System.out.println(c1.getName()) ; // 输出名字 Color c2 = Color.getInstance(3) ; // 根据编号取得名字 System.out.println(c2.getName()) ; } }; |
此时,程序限定了所能取的对象的范围,所以达到了枚举的功能。以上是一种枚举的方式,在最早的JAVA开发中因为没有枚举这种概念,所以有时候也使用接口表示。
interface Color{ public static final int RED = 1 ; // 定义红色 public static final int GREEN = 2 ; // 定义绿色 public static final int BLUE = 3 ; // 定义蓝色 } |
因为以上的所有取值是直接通过数字表示的,所以操作的时候也存在问题。
interface Color{ public static final int RED = 1 ; // 定义红色 public static final int GREEN = 2 ; // 定义绿色 public static final int BLUE = 3 ; // 定义蓝色 } public class ColorDemo02{ public static void main(String args[]){ System.out.println(Color.RED + Color.GREEN) ; // 颜色相加 } }; |
这样的操作并不会很明确,所以在JDK1.5之前如果要想实现枚举的操作,则就会比较麻烦。所以,在JDK1.5之后,引入了一个新的关键字类型——enum,可以直接定义枚举类型,格式如下:
·[public] enum 枚举类型名称{
枚举对象1,枚举对象2,……,枚举对象n;
}
使用enum关键字定义:
public enum Color{ RED,GREEN,BLUE ; // 定义三个枚举的类型 }; |
枚举中有三个取值。
以后在取得的时候,只能从这三个内容取
public class GetEnumContent{ public static void main(String args[]){ Color c = Color.BLUE ; // 取出蓝色 System.out.println(c) ; } }; |
因为枚举已经指定好了范围,所以可以使用foreach进行全部的输出,使用“枚举.values()”的形式取得全部的枚举内容。
public class PrintEnum{ public static void main(String args[]){ for(Color c:Color.values()){ // 输出枚举中的全部内容 System.out.println(c) ; } } }; |
还可以直接将内容在SWITCH语句上使用。
public class SwitchPrintEnum{ public static void main(String args[]){ 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("未知颜色") ; break ; } } } }; |
总结:
- 使用枚举可以限制取值的范围
- 使用enum关键字可以定义枚举
、Enum
Enum关键字表示的是java.lang.Enum类型,即:使用enum声明的枚举类型,就相当于定义一个类,而此类则默认继承Java.lang.Enum类。
Java.lang.Enum类的定义如下:
public abstract class Enum |
此类定义的时候使用了泛型机制,而且实现了Comparable接口以及Serializable接口,证明此种类型是可以比较,可以被序列化的。
枚举类的主要操作方法
NO | 方法 | 类型 | 描述 |
1 | protected Enum(String name,int ordinal) | 构造 | 接收枚举的名称和枚举的常量创建枚举对象 |
2 | protected final Object clone() throws CloneNotSupportedException | 普通 | 克隆枚举对象 |
3 | public final int compareTo(E o) | 普通 | 对象比较 |
4 | public final Boolean equals(Object other) | 普通 | 比较两个枚举对象 |
5 | public final int hashCode() | 普通 | 返回枚举常量的哈希码 |
6 | public final String name() | 普通 | 返回此枚举的名称 |
7 | public final int ordinal() | 普通 | 返回枚举常量的充数 |
8 | public static | 普通 | 返回带指定名称的指定枚举类型的枚举常量 |
Enum类的构造方法:
protected Enum(String name,int ordinal) |
构造方法中接收两个参数,一个表示枚举的名字,另外一个表示枚举的序号。
public enum Color{ RED,GREEN,BLUE; } |
RED实际上就表示的是枚举的名称,默认的编号是0。
public class GetEnumInfo{ public static void main(String args[]){ for(Color c:Color.values()){ System.out.println(c.ordinal()+“”+c.name()); } } } |
如果此时,希望做些改进,希望可以使用一些文字表示颜色的信息,则可以按照最早的Color类的形式,在枚举类中定义属性及自己的构造方法,但是一旦定义有参构造之后,在声明枚举对象的时候就必须明确的调用构造方法,并传递参数。
enum Color{ RED("红色"),GREEN("绿色"),BLUE("兰色") ; private Color(String name){ this.setName(name) ; } private String name ; // 定义name属性 public void setName(String name){ this.name = name ; } public String getName(){ return this.name ; } } public class ConstructorEnum{ public static void main(String args[]){ for(Color c:Color.values()){ System.out.println(c.ordinal() + " --> " + c.name() +"(" + c.getName() + ")") ; } } }; |
如果现在不想通过构造设置内容,而是希望通过setter()方法设置内容,则就必须按如下的方式执行:
enum Color{ RED,GREEN,BLUE ; private String name ; // 定义name属性 public void setName(String name){ switch(this){ // 判断操作的是那个枚举对象 case RED:{ if("红色".equals(name)){ this.name = name ; // 允许设置名字 }else{ System.out.println("设置内容错误。") ; } break ; } case GREEN:{ if("绿色".equals(name)){ this.name = name ; // 允许设置名字 }else{ System.out.println("设置内容错误。") ; } break ; } case BLUE:{ if("蓝色".equals(name)){ this.name = name ; // 允许设置名字 }else{ System.out.println("设置内容错误。") ; } break ; } } this.name = name ; } public String getName(){ return this.name ; } } public class SetEnum{ public static void main(String args[]){ Color c = Color.BLUE ; // 得到兰色 c.setName("兰色") ; // 名字错误 c.setName("蓝色") ; // 名字正确 System.out.println(c.getName()) ; } }; |
发现,使用构造方法更为方便。
enum Color{ RED,GREEN,BLUE ; private String name ; // 定义name属性 public void setName(String name){ switch(this){ // 判断操作的是那个枚举对象 case RED:{ if("红色".equals(name)){ this.name = name ; // 允许设置名字 }else{ System.out.println("设置内容错误。") ; } break ; } case GREEN:{ if("绿色".equals(name)){ this.name = name ; // 允许设置名字 }else{ System.out.println("设置内容错误。") ; } break ; } case BLUE:{ if("蓝色".equals(name)){ this.name = name ; // 允许设置名字 }else{ System.out.println("设置内容错误。") ; } break ; } } this.name = name ; } public String getName(){ return this.name ; } } public class ValueOfEnum{ public static void main(String args[]){ Color c = Color.valueOf(Color.class,"BLUE") ; // 得到兰色 c.setName("兰色") ; // 名字错误 c.setName("蓝色") ; // 名字正确 System.out.println(c.getName()) ; } }; |
对于”枚举.class”是属于java反射机制中的内容。
在枚举中实际上已经实现好了Comparable接口,所以枚举中的内容是可以排序的。
import java.util.Iterator; import java.util.Set ; import java.util.TreeSet ; enum Color{ RED,GREEN,BLUE ; } public class ComparableEnum{ public static void main(String args[]){ Set t.add(Color.GREEN) ; // 加入绿色 t.add(Color.RED) ; // 加入红色 t.add(Color.BLUE) ; // 加入蓝色 Iterator while(iter.hasNext()){ System.out.print(iter.next() + "、") ; } } }; |
、类集对枚举的支持
在JDK1.5的java.util程序包中提供两个新的集合操作类:EnumMap和EnumSet,这两个类与枚举类型的结合应用可使以前非常繁琐的程序变得简单方便。EnumSet类提供了java.util.Set接口的一个特殊实现,而EnumMap类提供了java.util.Map接口的一个特殊实现,该类中的键(key)是一个枚举类型。
、EnumMap
EnumMap类的定义:
public class EnumMap |
EnumMap是Map接口的子类,所以本身还是以Map的形式进行操作,即:key value。如果要想使用EnumMap,则首先要创建EnumMap的对象,在创建此对象的时候必须指定要操作的枚举类型,所在地构造方法如下:
·public EnumMap(Class
范例:
import java.util.EnumMap ; import java.util.Map ; enum Color{ RED , GREEN , BLUE ; } public class EnumMapDemo{ public static void main(String args[]){ Map desc = new EnumMap desc.put(Color.RED,"红色") ; desc.put(Color.GREEN,"绿色") ; desc.put(Color.BLUE,"蓝色") ; System.out.println("====== 输出全部的内容 ======") ; for(Color c:Color.values()){ System.out.println(c.name() + " --> " + desc.get(c)) ; } System.out.println("====== 输出全部的键值 ======") ; for(Color c:desc.keySet()){ System.out.print(c.name() + "、") ; } System.out.println() ; System.out.println("====== 输出全部的内容 ======") ; for(String s:desc.values()){ System.out.print(s + "、") ; } } }; |
、EnumSet
EnumSet是Set接口的子类,所以里面的内容是无法重复的,在使用EnumSet的时候是不能直接使用关键字new为其进行实例化的,所以在此类中提供了很多的静态方法。
EnumSet类的常用方法
NO | 方法 | 类型 | 说明 |
1 | public static | 普通 | 将枚举中的全部内容设置到EnumSet之中 |
2 | public static | 普通 | 创建一个包含枚举指定内容的EnumSet对象 |
3 | public static | 普通 | 创建一个从指定Collection中指定的EnumSet对象 |
4 | public static | 普通 | 创建一个其元素类型与指定枚举set 相同的枚举set,最初包含指定集合中所不包含的此类型的所有元素 |
5 | public static | 普通 | 创建一个可以接收指定类的空集合 |
依次验证EnumSet类的方法
·范例:将全部的集合设置到EnumSet集合之中
import java.util.EnumSet ; enum Color{ RED , GREEN , BLUE ; } public class EnumSetDemo01{ public static void main(String args[]){ EnumSet System.out.println("======== EnumSet.allOf(Color.class) =====") ; es = EnumSet.allOf(Color.class) ; // 将枚举的全部类型设置到EnumSet对象之中 print(es) ; } public static void print(EnumSet for(Color c:temp){ // 循环输出EnumSet中的内容 System.out.print(c + "、") ; } System.out.println() ; } }; |
·范例:只设置一个内容到集合
import java.util.EnumSet ; enum Color{ RED , GREEN , BLUE ; } public class EnumSetDemo02{ public static void main(String args[]){ EnumSet System.out.println("======== EnumSet.of(Color.BLUE) =====") ; es = EnumSet.of(Color.BLUE) ; // 将枚举的全部类型设置到EnumSet对象之中 print(es) ; } public static void print(EnumSet for(Color c:temp){ // 循环输出EnumSet中的内容 System.out.print(c + "、") ; } System.out.println() ; } }; |
创建只能放入指定枚举类型的集合
·可能同时有多个类型的枚举对象,但是一个集合中只要求放入指定类型的枚举
import java.util.EnumSet ; enum Color{ RED , GREEN , BLUE ; } public class EnumSetDemo03{ public static void main(String args[]){ EnumSet System.out.println("======== EnumSet.noneOf(Color.class) =====") ; es = EnumSet.noneOf(Color.class) ; // 将枚举的全部类型设置到EnumSet对象之中 es.add(Color.RED) ; // 增加内容 es.add(Color.GREEN) ; // 增加内容 print(es) ; } public static void print(EnumSet for(Color c:temp){ // 循环输出EnumSet中的内容 System.out.print(c + "、") ; } System.out.println() ; } }; |
还可以创建不包含指定元素的集合:
import java.util.EnumSet ; enum Color{ RED , GREEN , BLUE ; } public class EnumSetDemo04{ public static void main(String args[]){ EnumSet EnumSet System.out.println("======== EnumSet.complementOf(Color.class) =====") ; esOld = EnumSet.noneOf(Color.class) ; // 将枚举的全部类型设置到EnumSet对象之中 esOld.add(Color.RED) ; // 增加内容 esOld.add(Color.GREEN) ; // 增加内容 esNew = EnumSet.complementOf(esOld) ; // 不包含指定内容 print(esNew) ; } public static void print(EnumSet for(Color c:temp){ // 循环输出EnumSet中的内容 System.out.print(c + "、") ; } System.out.println() ; } }; |
还可以拷贝一个集合的内容:
import java.util.EnumSet ; enum Color{ RED , GREEN , BLUE ; } public class EnumSetDemo05{ public static void main(String args[]){ EnumSet EnumSet System.out.println("======== EnumSet.copyOf(Color.class) =====") ; esOld = EnumSet.noneOf(Color.class) ; // 将枚举的全部类型设置到EnumSet对象之中 esOld.add(Color.RED) ; // 增加内容 esOld.add(Color.GREEN) ; // 增加内容 esNew = EnumSet.copyOf(esOld) ; // 从已有的集合拷贝过来 print(esNew) ; } public static void print(EnumSet for(Color c:temp){ // 循环输出EnumSet中的内容 System.out.print(c + "、") ; } System.out.println() ; } }; |
总结:
·EnumMap和EnumSet,EnumMap是符合Map的操作形式的,而EnumSet基本上就是都使用静态方法完成。
·在操作中大量的使用了“枚举.class”,这个属于JAVA的反射机制。
、枚举的其他应用
枚举类型可以跟普通的类一样实现一个接口,但是实现接口的时候要求枚举中的每个对象都必须单独覆写好接口中的抽象方法。
interface Print{ public String getColor() ; } enum Color implements Print{ RED{ public String getColor(){ return "红色" ; } },GREEN{ public String getColor(){ return "绿色" ; } },BLUE{ public String getColor(){ return "蓝色" ; } } ; } public class InterfaceEnumDemo{ public static void main(String args[]){ for(Color c:Color.values()){ System.out.print(c.getColor() + "、") ; } } }; |
还可以直接在枚举中定义抽象方法,但是要求枚举中的每个对象都分别实现此抽象方法。
enum Color implements Print{ RED{ public String getColor(){ return "红色" ; } },GREEN{ public String getColor(){ return "绿色" ; } },BLUE{ public String getColor(){ return "蓝色" ; } } ; public abstract String getColor() ; } public class AbstractMethodEnum{ public static void main(String args[]){ for(Color c:Color.values()){ System.out.print(c.getColor() + "、") ; } } }; |
总结:
·枚举的最大作用在于限定取值范围,在随后的Annotation中也会接触到。
·如果已经习惯了使用其他语言的枚举操作,可能会适应JAVA的枚举开发习惯,而如果没有相关枚举开发经验的话,那么也不是很建议使用枚举。