- 关键字enum可以将一组具名的值得优先级和创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用
- enum的定义和使用方式方式:
-
123456789101112131415161718
enum
Shrubbery {GROUND, CRAWLING, HANGING}
public
class
EnumClass {
public
static
void
main(String[] args) {
// TODO Auto-generated method stub
for
(Shrubbery s : Shrubbery.values()){
System.out.println(s +
" ordinal:"
+ s.ordinal());
System.out.println(s.compareTo(Shrubbery.CRAWLING) +
" "
);
System.out.println(s.equals(Shrubbery.CRAWLING));
System.out.println(s == Shrubbery.CRAWLING);
System.out.println(s.getDeclaringClass());
System.out.println(s.name());
System.out.println();
}
}
}
- values()返回enum实例数组,并且该数组的元素严格保持其在enum中声明时的顺序
- ordinal()方法返回一个int值,表示每个enum实例在声明时的次序
- 可以直接使用==来比较enum实例,编译器会自动为你提供equals()和hashCode()方法。Enum类实现了Comparable接口,所以它具有compareTo()方法。同时它还实现了Serializable接口
- getDeclaringClass()方法可以获得其所属的enum类
- name()方法与使用toString()方法效果相同,返回enum实例声明时的名字
- valueOf()是Enum中定义的static方法,根据给定的名字返回相应的enum实例,如果不存在给定名字的实例,将会抛出异常
-
- 静态导入enum:
- 使用方式:
-
12345678910111213141516171819
package
enumTest;
public
enum
Spiciness {
NOT, MILD, MEDIUM, HOT, FLAMING
}
package
enumTest;
import
static
enumTest.Spiciness.*;
public
class
Burrito {
public
static
void
main(String[] args) {
System.out.println(NOT.ordinal());
System.out.println(MILD);
System.out.println(MEDIUM.equals(MILD));
}
}
- 通过static import,可以使enum实例的标识符带入当前的命名空间,所以无需再用enum类型来修是谁enum实例
-
- 使用方式:
- enum不能被继承,除此之外可以将其看作是一个常规的类,可以向其中添加方法,甚至可以有main()方法
-
1234567891011121314151617181920212223
package
enumTest;
public
enum
OzWitch {
WEST(
"This is west"
),
NORTH(
"This is north"
),
EAST(
"This is east"
),
SOUTH(
"This is center"
);
private
String description;
private
OzWitch(String description) {
this
.description = description;
}
public
String getDescription(){
return
description;
}
public
static
void
main (String[] args) {
for
(OzWitch witch : OzWitch.values()){
System.out.println(witch.toString() +
":"
+ witch.getDescription());
}
}
}
-
- values()的神秘之处
- 编译器创建的enum类都继承自Enum类,然而Enum类中并没有values()方法。values()方法是由编译器添加的static方法,在创建一个enum类时,编译器还为其添加了valueOf()方法,在Enum中的valueOf()需要两个参数,而这个新增的valueOf()方法只需要一个
- 编译器还将enum类标记为final类,所以无法继承自enum类
- 由于values()方法是由编译器插入到enum定义中的static方法,所以如果将enum实例向上转型为Enum,那么values()方法就不可访问了。
- 在Class中有一个getEnumConstants()方法, 可以通过Class对象取得所有的enum实例。这个方法时Class上的方法,甚至可以对不是枚举的类调用此方法并返回null
- 实现,而非继承
- 所有的enum类都继承自java.lang.Enum类,由于Java不支持多重继承,所以enum不能继承其他类
- 随机选取:
-
12345678910111213141516171819202122232425262728293031
package
enumTest;
enum
Activity {SITTING, LYING, STANDING, HOPPING, RUNNING, DODGING, JUMPING, FALLING, FLYING}
public
class
RandomTest {
public
static
void
main(String[] args) {
for
(
int
i =
0
; i <
20
; i++){
System.out.println(Enums.random(Activity.
class
));
}
}
}
package
enumTest;
import
java.util.Random;
public
class
Enums {
private
static
Random rand =
new
Random(
47
);
public
static
<T
extends
Enum<T>>T random(Class<T> ec){
return
random(ec.getEnumConstants());
}
public
static
<T> T random(T[] values){
return
values[rand.nextInt(values.length)];
}
}
-
- 使用接口组织枚举:
- 对于enum而言,实现接口是使其子类化的唯一方法,所以嵌入在Food中的每个enum都实现了Food接口
-
12345678910111213141516171819202122232425
package
enumTest;
public
interface
Food {
enum
Appetizer
implements
Food{
SALAD, SOUP, SPRINT_ROLLS;
}
enum
MainCourse
implements
Food{
LASAGNE, BURRITO, PAD_THAI, LENTITLS, HUMMOUS, VINDALOO;
}
//And so on....
}
package
enumTest;
import
static
enumTest.Food.*;
public
class
TypeOfFood {
public
static
void
main(String[] args) {
Food food = Appetizer.SALAD;
food = MainCourse.BURRITO;
}
}
-
- 如果类型数量较多,接口就不如enum好用了,可以建立枚举的枚举,甚至是在enum中嵌套enum
-
123456789101112131415161718192021222324252627282930313233343536373839404142
package
enumTest;
public
enum
Meal {
APPETIZER(Food.Appetizer.
class
),
MAINCOURSE(Food.MainCourse.
class
),
DESSERT(Food.Dessert.
class
),
COFFEE(Food.Coffee.
class
);
private
Food[] values;
private
Meal(Class<?
extends
Food> kind){
values = kind.getEnumConstants();
}
public
interface
Food {
enum
Appetizer
implements
Food{
SALAD, SOUP, SPRING_ROLLS;
}
enum
MainCourse
implements
Food{
LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALLO;
}
enum
Dessert
implements
Food{
TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, VREME_CARAMEL;
}
enum
Coffee
implements
Food {
BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA;
}
}
public
Food randomSelection(){
return
Enums.random(values);
}
public
static
void
main (String[] args){
for
(
int
i =
0
; i <
5
; i++){
for
(Meal meal : Meal.values()){
Food food = meal.randomSelection();
System.out.println(food);
}
System.out.println(
"---"
);
}
}
}
-
- 对于enum而言,实现接口是使其子类化的唯一方法,所以嵌入在Food中的每个enum都实现了Food接口
- 使用EnumSet替代标志:
- Java SE5中引入EnumSet,为了通过enum创建一种替代品,以替代传统的基于int的“位操作”。这种标志可以用来表示某种“开/关”信息。
- EnumSet的设计充分考虑到了速度因素,其操作与HashSet相比,非常的快,就其内部而言,它(可能)就是将一个long值作为b比特向量。
- 使用EnumSet的优点是:说明一个二进制位是否存在,具有更好的表达能力,并且无需担心性能
- EnumSet的元素必须来源于一个enum
- 使用实例:
-
12345678910111213141516171819202122232425
package
enumTest;
import
static
enumTest.AlarmPoints.*;
import
java.util.EnumSet;
public
class
EnumSets {
public
static
void
main(String[] args) {
EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.
class
);
points.add(BATHROOM);
System.out.println(points);
points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
System.out.println(points);
points = EnumSet.allOf(AlarmPoints.
class
);
System.out.println(points);
points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
System.out.println(points);
points.removeAll(EnumSet.range(OFFICE1,OFFICE4));
System.out.println(points);
points = EnumSet.complementOf(points);
System.out.println(points);
}
}
-
12345
package
enumTest;
public
enum
AlarmPoints {
STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN
}
- of方法被重载了很多次,因为其实只是用可变参数已经可以解决整个问题,但是对比显示的参数会有一点性能损失。当使用一个参数或多过5个参数时,调用的僵尸使用可变参数的of()方法,由于使用一个参数时,编译器不会构造可变参数的数组所以调用一个参数没有额外的性能消耗
-
- EnumSet的基础是long,一个long值有64位,但EnumSet可以应用于多过64个元素的enum,所以猜测,Enum会在必要的时候增加一个long
- 使用EnumMap:
- EnumMap是一种特殊的Map,它要求其中的键必须来自一个enum。由于enum本身的限制,所以EnumMap在内部可由数组实现,因此EnumMap的速度非常快。除了必须使用enum的实例作为键来调用put()方法以外,其他和一般的Map差不多
-
1234567891011121314151617181920212223242526272829303132333435363738394041424344
package
enumTest;
import
static
enumTest.AlarmPoints.*;
import
java.util.EnumMap;
import
java.util.Map;
public
class
EnumMaps {
interface
Command{
void
action();
}
public
static
void
main(String[] args) {
EnumMap<AlarmPoints, Command> em =
new
EnumMap<AlarmPoints, Command>(AlarmPoints.
class
);
em.put(KITCHEN,
new
Command() {
@Override
public
void
action() {
System.out.println(
"Kitchen fire"
);
}
});
em.put(BATHROOM,
new
Command() {
@Override
public
void
action() {
System.out.println(
"Bathroom fire"
);
}
});
for
(Map.Entry<AlarmPoints, Command> e : em.entrySet()){
System.out.print(e.getKey() +
":"
);
e.getValue().action();
}
}
}
package
enumTest;
public
enum
AlarmPoints {
STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN
}
- 与EnumSet一样,EnumMap中的顺序由enum实例决定
- 可以使用enum实现职责连
- 枚举类型非常适合用来创建状态机。一个状态机可以具有有限个特定的状态,它通常根据输入,从一个状态转移到下一个状态,不过也可能存在瞬时状态,而一旦人数执行结束,状态机就会立即离开瞬时状态
《Java 编程思想》--第十九章:枚举类型
最新推荐文章于 2013-05-31 23:51:39 发布