2 Enumerated Types
2.1 创建enum
创建enum类型必须包括至少3个基本成分
A:enum关键字
B:enum类的名字
C:一组该类的值
一些其他可定义的成分
D:一些enum要实现的接口
E:变量定义
F:方法定义
G:特殊的赋值
看一下代码:
public enum Grade {
A, B, C, D, F, INCOMPLETE
}
public class Student {
private String name;
private Grade grade;
public Student(String name){
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void assignGrade(Grade grade) {
this.grade = grade;
}
public Grade getGrade() {
return grade;
}
/**
* @param args
*/
public static void main(String[] args) {
Student studentA = new Student("A");
Student studentB = new Student("B");
Student studentC = new Student("C");
studentA.assignGrade(Grade.B);
studentB.assignGrade(Grade.INCOMPLETE);
studentC.assignGrade(Grade.A);
}
}
注意:
A:你可以把所有的public static final的变量在enum类中声明
B:大部分时候,你只需要使用enum的基本功能
C:按照约定用大写字符定义你的enum
D:enum类像一般的class类被引用
以下是enum的基本概念:
A:enum是类
B:所有的enum类都继承java.lang.Enum
C:enum类中定义的值不是integer,而是一个java.lang.Enum的实例
D:enum类没有公有的构造器,这是为了防止创建新的值
E:enum类中的所有值都是public static final的(Enums are not "final" when they have value-specific methods)
F:enum的值可以用=或或者equasl()来计较
G:enum类都实现了java.lang.Comparable
H:enum类override toString()方法,返回类中value的name,如Grade.INCOMPLETE.toString()返回"INCOMPLETE",toString()方法不是fianl,你可以override
I:enum类提供一个valueOf()方法,如Grade.valueOf("INCOMPLETE")返回Grade.INCOMPLETE
J:enum类提供一个final的方法ordinal(),返回整形的各enum值在enum类中的位置,从0开始
K:enum类提供values()方法,返回enum类中enum值的集合
2.2 Declaring Enums Inline
看一下代码
public class Downloader {
public enum DownloadStatus { INITIALIZING, IN_PROGRESS, COMPLETE };
.
.
}
需要说明的是申明DownloadStatus就不需要再用static修饰了
2.3 Switching on Enums
看一下代码
public static void switchStatement(Student student) {
switch (student.getGrade()) {
case A:
break;
case B:
break;
case C:
break;
case D:
break;
case F:
break;
case INCOMPLETE:
break;
default:
break;
}
}
需要注意的是在这里case A而不是case Grade.A;这里只是为了简化写法,和static import没有关系
switch语句最好加上default处理,说不定有人会修改enum类,这样你的switch语句还是可以处理unknown conditions
2.4 Maps of Enums
看一下以前的写法
public static final int INITIALIZING = 0;
public static final int COMPILING = 1;
public static final int COPYING = 2;
public static final int JARRING = 3;
public static final int ZIPPING = 4;
public static final int DONE = 5;
public static final int ERROR = 6;
public static String[] antMessages = new String[] {
"Initalizing Ant...", // INITIALIZING
"Compiling Java classes...", // COMPILING
"Copying files...", // COPYING
"JARring up files...", // JARRING
"ZIPping up files...", // ZIPPING
"Build complete.", // DONE
"Error occurred." // ERROR
};
public static void main(String[] args) {
.
.
int antStatus = antProcess.getStatus();
System.out.println("ant> " + antMessages[antStatus]);
.
}
使用EnumMap的写法
public enum AntStatus {
INITIALIZING, COMPILING, COPYING, JARRING, ZIPPING, DONE, ERROR
}
import java.util.EnumMap;
public class AntEnumMap {
/**
* @param args
*/
public static void main(String[] args) {
EnumMap antMessages = new EnumMap(AntStatus.class);
antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");
antMessages.put(AntStatus.COMPILING, "Compiling Java classes...");
antMessages.put(AntStatus.COPYING, "Copying files...");
antMessages.put(AntStatus.JARRING, "JARring up files...");
antMessages.put(AntStatus.ZIPPING, "ZIPping up files...");
antMessages.put(AntStatus.DONE, "Build complete.");
antMessages.put(AntStatus.ERROR, "Error occurred.");
for (AntStatus status : AntStatus.values()) {
System.out.println("For status " + status + ", message is: " + antMessages.get(status));
}
}
}
附件的好处是初始化EnumMap的时候不需要排序,保证enums对应message的正确性
感觉优化不是很明显,还是那么多代码要写;在创建EnumMap对象的时候如果可以写成new EnumMap(AntStatus.class,String[] strings)从而在内部完成map的装载是不是更方便?
2.5 Sets of Enums
看一下代码
public enum GuitarFeatures {
ROSEWOOD, // back/sides
MAHOGANY, // back/sides
ZIRICOTE, // back/sides
SPRUCE, // top
CEDAR, // top
AB_ROSETTE, // abalone rosette
AB_TOP_BORDER, // abalone top border
IL_DIAMONDS, // diamond/square inlay
IL_DOTS // dots inlays
}
import java.util.EnumSet;
public class GuitarEnumSet {
public static void main(String[] args) {
EnumSet allFeatures = EnumSet.allOf(GuitarFeatures.class);
EnumSet backSides = EnumSet.of(GuitarFeatures.ROSEWOOD,
GuitarFeatures.MAHOGANY,
GuitarFeatures.ZIRICOTE);
EnumSet bourgeoisD150 = EnumSet.of(GuitarFeatures.ROSEWOOD,
GuitarFeatures.SPRUCE,
GuitarFeatures.AB_ROSETTE,
GuitarFeatures.IL_DIAMONDS);
boolean hasAbRosette = bourgeoisD150.contains(GuitarFeatures.AB_ROSETTE);
}
}
详细看一下api
2.6 Adding Methods to an Enum
看一下代码:
public enum GuitarFeatures {
ROSEWOOD(0), // back/sides
MAHOGANY(0), // back/sides
ZIRICOTE(300), // back/sides
SPRUCE(0), // top
CEDAR(0), // top
AB_ROSETTE(75), // abalone rosette
AB_TOP_BORDER(400), // abalone top border
IL_DIAMONDS(150), // diamond/square inlay
IL_DOTS(0); // dots inlays
private float upcharge;
GuitarFeatures(float upcharge){
this.upcharge = upcharge;
}
public float getUpcharge() {
return upcharge;
}
}
为enum类添加了带float参数构造方法,类中的每个枚举值的声明都要将使用此构造方法;枚举值的定义以分号结束;变量upcharge的申明不能放到枚举值的申明之前;枚举类的构造方法是私有的,不能申明为public
2.7 Implementing Interfaces with Enums
首先构造一个interface类
public interface Features {
public float getUpcharge();
}
修改enum类的定义为:
public enum GuitarFeatures implements Features {
.
.
}
2.8 Value-Specific Class Bodies
看一下代码
enum Opcode {
PUSH(1) {
public void perform(StackMachine machine, int[] operands) {
machine.push(operands[0]);
}
},
ADD(0) {
public void perform(StackMachine machine, int[] operands) {
machine.push(machine.pop( ) + machine.pop( ));
}
},
BEZ(1) {
public void perform(StackMachine machine, int[] operands) {
if (machine.pop( ) == 0) machine.setPC(operands[0]);
}
};
Opcode(int numOperands) { this.numOperands = numOperands; }
int numOperands;
public abstract void perform(StackMachine machine, int[] operands);
}
之前说过enum都是final的,除了在Value-Specific Class Bodies的情况下,实事上,上面的编码看,每个enum value都创建了一个匿名子类,编译后,除了enum类本身外,多了几个enum value的子类,又从反编译class文件看到一般的enum类都会被声明为final,而这里没有.
以上的写法往往在debug时很麻烦,以前在debug ejb代码的时候也是碰到,系统会帮你生成一些非代码级的代码调用,看一下简单的实现:
enum Opcode {
PUSH(1), ADD(0), BEZ(1);
int numOperands;
Opcode(int numOperands){
this.numOperands = numOperands;
}
public void perform(StackMachine machine, int[] operands) {
switch (this) {
case PUSH:
machine.push(operands[0]);
break;
case ADD:
machine.push(machine.pop() + machine.pop());
break;
case BEZ:
if (machine.pop() == 0) machine.setPC(operands[0]);
break;
default:
throw new AssertionError();
}
}
}
心情: 一般