枚举类型-enum
来源:互联网 发布:如何自学数控编程 编辑:程序博客网 时间:2024/06/06 12:34
前言:枚举时Java SE5中的新特性,枚举类型的关键字为enum。在创建enum时编译器会自动添加一些有用的特性,在API中却没有显示,所以需要注意一下。
1. 基础
枚举类型的定义格式为:
enum <枚举类型名> {<枚举表>};
1.1 编译器自动添加
在创建enum的时候,编译器会自动添加一些有用的特性。例如,会创建toString()方法,以便可以方便地显示某个enum实例的名字;会创建ordinal()方法,用来表示某个enum常量的声明顺序;创建 static values()方法,用来按照enum常量的声明书序,产生由这些常量值构成的数组。
示例:
定义一个枚举类型:
public enum Spiciness { NOT, MILD, MEDIUM, HOT, FLAMING}测试用例:
public class EnumOrder { public static void main(String[] args) { for(Spiciness s : Spiciness.values()) System.out.println(s + ", ordinal " + s.ordinal()); }}输出结果:
NOT, ordinal 0MILD, ordinal 1MEDIUM, ordinal 2HOT, ordinal 3FLAMING, ordinal 4详细的原因可以参考:Java Enum 类 的 values()方法 api没有,实例是怎么调用的?
注意:enum实例在声明时的顺序是从0开始的。可以使用==来比较enum实例,编译器会自动为你提供equals()和hashCode()方法。Enum类实现了Comparable借口,所以具有compareTo()方法,同时也实现了Serializable接口。
在enum实例上调用getDeclaring()方法,我们就能知道其所属的enum类;name()方法返回enum实例声明时的名字,这与使用toString()方法效果相同;valueOf()是在Enum中定义的static方法,可以根据给定的名字返回相应的enum实例,如果不存在给定名字的实例,将会抛出异常。
示例:
import static net.mindview.util.Print.*;enum Shrubbery { GROUND, CRAWLING, HANGING }public class EnumClass { public static void main(String[] args) { for(Shrubbery s : Shrubbery.values()) { print(s + " ordinal: " + s.ordinal()); printnb(s.compareTo(Shrubbery.CRAWLING) + " "); printnb(s.equals(Shrubbery.CRAWLING) + " "); print(s == Shrubbery.CRAWLING); print(s.getDeclaringClass()); print(s.name()); print("----------------------"); } // Produce an enum value from a string name: for(String s : "HANGING CRAWLING GROUND".split(" ")) { Shrubbery shrub = Enum.valueOf(Shrubbery.class, s); print(shrub); } }} /* Output:GROUND ordinal: 0-1 false falseclass ShrubberyGROUND----------------------CRAWLING ordinal: 10 true trueclass ShrubberyCRAWLING----------------------HANGING ordinal: 21 false falseclass ShrubberyHANGING----------------------HANGINGCRAWLINGGROUND*/其中net.mindview.util.Print是一个简单的工具类,只是将输出封装了一下,完全可以更改一下,或者可以从《Java编程思想》随书代码中找到,链接为:http://download.csdn.net/detail/fanxiaobin577328725/9714670
1.2 静态导入enum
使用static import能够将enum的标识符带入当前的命名空间,所以无需要用enum类型来修饰enum实例。编译器可以确保你使用的是正确的类型,但是需要注意的是,使用静态导入会导致代码令人难以理解。这也是静态导入的缺点,所以谨慎使用。
注意:在定义enum的同一个文件中,以及在默认包中定义enum时,无法使用静态导入。
示例:
//: enumerated/Spiciness.javapackage enumerated;public enum Spiciness { NOT, MILD, MEDIUM, HOT, FLAMING}测试用例:
//: enumerated/Burrito.javapackage enumerated;import static enumerated.Spiciness.*;public class Burrito { Spiciness degree; public Burrito(Spiciness degree) { this.degree = degree;} public String toString() { return "Burrito is "+ degree;} public static void main(String[] args) { System.out.println(new Burrito(NOT)); System.out.println(new Burrito(MEDIUM)); System.out.println(new Burrito(HOT)); }} /* Output:Burrito is NOTBurrito is MEDIUMBurrito is HOT*/
1.3 向enum中添加新方法
除了不能继承一个enum之外,我们基本可以将enum看做一个常规的类。也就是说:我们可以向enum中添加方法,甚至是main()方法。
默认的toString()方法只能返回枚举实例的名字,但是我们有时希望每个枚举实例能够返回对自身的描述。为此,我们可以提供一个构造器,专门负责处理这个额外的信息,然后添加 一个方法,返回这个描述信息。
示例:
//: enumerated/OzWitch.java// The witches in the land of Oz.package enumerated;import static net.mindview.util.Print.*;public enum OzWitch { // Instances must be defined first, before methods: WEST("Miss Gulch, aka the Wicked Witch of the West"), NORTH("Glinda, the Good Witch of the North"), EAST("Wicked Witch of the East, wearer of the Ruby " + "Slippers, crushed by Dorothy's house"), SOUTH("Good by inference, but missing"); private String description; // Constructor must be package or private access: private OzWitch(String description) { this.description = description; } public String getDescription() { return description; } public static void main(String[] args) { for(OzWitch witch : OzWitch.values()) print(witch + ": " + witch.getDescription()); }} /* Output:WEST: Miss Gulch, aka the Wicked Witch of the WestNORTH: Glinda, the Good Witch of the NorthEAST: Wicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's houseSOUTH: Good by inference, but missing*/
注意:如果打算定义自己的方法,那么必须在enum实例序列的最后添加一个分号。同时,Java要求你必须先定义enum示例。
在上面的这个例子中,虽然构造器时private,但是对于他的可访问性,其实并没有什么变化。因为(即使不声明为private)我们只能在enum定义的内部使用其构造器创建enum实例。一旦enum的定义结束,编译器就不允许我们再使用其构造器来创建任何实例了。
1.4 switch语句中的enum
一般情况下在switch中只能使用整数值,而枚举实例天生就具备整数值的次序,并且可以通过ordinal()方法取得其次序(文章开头提及),因此我们可以在switch语句中使用enum。
虽然一般情况下我们必须使用enum类型来修饰一个enum实例,但是在case语句中却不必如此。
示例:
//: enumerated/TrafficLight.java// Enums in switch statements.package enumerated;import static net.mindview.util.Print.*;// Define an enum type:enum Signal { GREEN, YELLOW, RED, }public class TrafficLight { Signal color = Signal.RED; public void change() { switch(color) { // Note that you don't have to say Signal.RED // in the case statement: case RED: color = Signal.GREEN; break; case GREEN: color = Signal.YELLOW; break; case YELLOW: color = Signal.RED; break; } } public String toString() { return "The traffic light is " + color; } public static void main(String[] args) { TrafficLight t = new TrafficLight(); for(int i = 0; i < 7; i++) { print(t); t.change(); } }} /* Output:The traffic light is REDThe traffic light is GREENThe traffic light is YELLOWThe traffic light is REDThe traffic light is GREENThe traffic light is YELLOWThe traffic light is RED*///:~注意:此示例中的switch中没有default但是仍然编译通过,并正常运行,如果我们去除其中某个case分支也是正常的。这就意味着,我们必须自己去确保覆盖所有的分支。但是,如果在case语句中调用return,那么编译器就会强制要求有default语句了。
2. 高级
2.1 values()方法
编译器创建的enum类都继承自java.lang.Enum类,我们都知道Java是单继承的,查看API发现没有这个方法,其实values()方法是有编译器添加的static方法。
由于values()方法是由编译器插入到enum定义中的static方法,所以你讲enum实例向上转型为Enum,那么values()方法就不可访问了,
示例:
//: enumerated/UpcastEnum.java// No values() method if you upcast an enumpackage enumerated;enum Search { HITHER, YON }public class UpcastEnum { public static void main(String[] args) { Search[] vals = Search.values(); Enum e = Search.HITHER; // Upcast// e.values(); // No values() in Enum for(Enum en : e.getClass().getEnumConstants()) System.out.println(en); }} /* Output:HITHERYON*///:~注意:因为getEnumConstants()是Class上的方法,所以我们可以对不是枚举的类调用此方法。
2.2 实现,而非继承
我们已经知道,所有的Enum都继承自java.lang.Enum类。由于Java不支持多重继承,所以你的Enum不能再继承其他类。然而,在我们创建一个新的enum时,可以同时实现一个或多个接口:
//: enumerated/cartoons/EnumImplementation.java// An enum can implement an interfacepackage enumerated.cartoons;import java.util.*;import net.mindview.util.*;enum CartoonCharacter implements Generator<CartoonCharacter> {SLAPPY, SPANKY, PUNCHY, SILLY, BOUNCY, NUTTY, BOB;private Random rand = new Random(47);public CartoonCharacter next() {return values()[rand.nextInt(values().length)];}}public class EnumImplementation {public static <T> void printNext(Generator<T> rg) {System.out.print(rg.next() + ", ");}public static void main(String[] args) {// Choose any instance:CartoonCharacter cc = CartoonCharacter.BOB;for (int i = 0; i < 10; i++)printNext(cc);}}/* * Output: BOB, PUNCHY, BOB, SPANKY, NUTTY, PUNCHY, SLAPPY, NUTTY, NUTTY, * SLAPPY, */// :~
2.3 随机选取
许多时候我们需要从enum实例中进行随机选择。我们可以利用泛型,从而使得这个工作更一般化,可以作为工具使用。
//: net/mindview/util/Enums.javapackage net.mindview.util;import java.util.*;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)]; }}理解这一段代码需要一点泛型的基础,其中<T extends Enum<T>>表示T是一个enum实例。下面是编写的使用示例:
//: enumerated/RandomTest.javapackage enumerated;import net.mindview.util.*;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.print(Enums.random(Activity.class) + " "); System.out.println(); System.out.println("-----------------------------------"); for(int i = 0; i < 20; i++) System.out.print(Enums.random(Activity.values()) + " "); }} /* Output:STANDING FLYING RUNNING STANDING RUNNING STANDING LYING DODGING SITTING RUNNING HOPPING HOPPING HOPPING RUNNING STANDING LYING FALLING RUNNING FLYING LYING -----------------------------------LYING HOPPING LYING JUMPING DODGING SITTING DODGING LYING RUNNING DODGING SITTING FALLING FALLING JUMPING LYING HOPPING LYING HOPPING RUNNING SITTING *///:~
2.4 使用接口组织枚举
有时我们需要扩展原来enum中的元素,或者希望使用子类将一个enum中的元素进行分类,但是无法从enum继承子类,很让人头痛。我们可以在一个借口的内部,创建实现该接口的枚举,以此将元素进行分组,可以达到枚举元素分类组织的目的。
举例来说:假设想用enum来表示不同的类别的食物,同时还希望每个enum元素仍然保持Food类型,实现如下:
//: enumerated/menu/Food.java// Subcategorization of enums within interfaces.package enumerated.menu;public interface Food { enum Appetizer implements Food { SALAD, SOUP, SPRING_ROLLS; } enum MainCourse implements Food { LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO; } enum Dessert implements Food { TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, CREME_CARAMEL; } enum Coffee implements Food { BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA; }}对于enum而言,实现接口是使其子类化的唯一办法,所以嵌入在Food中的每个enum都实现了Food接口,我们可以说“所有东西都是某种类型的Food”。因为enum类型实现了Food接口,那么我们就可以将其实例向上转型为Food
同样还有一种更简洁的管理枚举的办法,就是将一个enum嵌套在另一个enum内,如下:
//: enumerated/menu/Meal2.javapackage enumerated.menu;import net.mindview.util.*;public enum Meal2 { APPETIZER(Food.Appetizer.class), MAINCOURSE(Food.MainCourse.class), DESSERT(Food.Dessert.class), COFFEE(Food.Coffee.class); private Food[] values; private Meal2(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, VINDALOO; } enum Dessert implements Food { TIRAMISU, GELATO, BLACK_FOREST_CAKE, FRUIT, CREME_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(Meal2 meal : Meal2.values()) { Food food = meal.randomSelection(); System.out.println(food); } System.out.println("---"); } }}
3. 拓展
3.1 使用EnumSet替代标志
对集合有了解对EnumSet应该理解起来就不难了,Set是集合中的一种,其要求添加不重复的对象。enum也要求其成员都是唯一的,所以enum看起来也具有集合的行为,但是enum中是无法删除或添加元素,所以有点鸡肋了。Java SE 5引入EnumSet,是为了通过enum创建一种替代品,以替代传统的基于int的“位标志”,EnumSet中的元素必须来自一个enum。示例:
//: enumerated/AlarmPoints.javapackage enumerated;public enum AlarmPoints { STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY, KITCHEN}然后我们用EnumSet来进行操作:
//: enumerated/EnumSets.java// Operations on EnumSetspackage enumerated;import java.util.*;import static enumerated.AlarmPoints.*;import static net.mindview.util.Print.*;public class EnumSets { public static void main(String[] args) { EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class); // Empty set points.add(BATHROOM); print(points); points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN)); print(points); points = EnumSet.allOf(AlarmPoints.class); points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN)); print(points); points.removeAll(EnumSet.range(OFFICE1, OFFICE4)); print(points); points = EnumSet.complementOf(points); print(points); }} /* Output:[BATHROOM][STAIR1, STAIR2, BATHROOM, KITCHEN][LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY][LOBBY, BATHROOM, UTILITY][STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]*/
3.2 使用EnumMap
————————》》后期完善
  
参考资料:
《Java编程思想 第四版》
最后修改时间:2017年3月29日16:34:34
********************************************************************************结束语********************************************************************************************
我在写这篇博客的时候也是一名初学者,有任何疑问或问题请留言,或发邮件也可以,邮箱为:fanxiaobin.fxb@qq.com,我会尽早的进行更正及更改。
在我写过的博客中有两篇博客是对资源的整理,可能对大家都有帮助,大家有兴趣的话可以看看!!
下载资料整理——目录:http://blog.csdn.net/fanxiaobin577328725/article/details/51894331
这篇博客里面是我关于我见到的感觉不错的好资源的整理,里面包含了书籍及源代码以及个人搜索的一些资源,如果有兴趣的可以看看,我会一直对其进行更新和添加。
优秀的文章&优秀的学习网站之收集手册:http://blog.csdn.net/fanxiaobin577328725/article/details/52753638
这篇博客里面是我对于我读过的,并且感觉有意义的文章的收集整理,纯粹的个人爱好,大家感觉有兴趣的可以阅读一下,我也会时常的对其进行更新。
********************************************************************************感谢********************************************************************************************
- Java enum 枚举类型
- C#枚举类型enum
- C#枚举类型enum
- C#枚举类型enum
- enum枚举类型学习
- JAVA枚举类型Enum
- 枚举类型-enum使用
- C枚举类型enum
- C枚举类型enum
- 枚举类型------enum
- Enum 枚举类型
- [Java] enum 枚举类型
- Java enum 枚举类型
- c# 枚举 enum 类型
- java enum 枚举类型
- c++ 枚举类型 enum
- enum枚举类型
- 枚举类型 enum
- 《C++ Primer Plus(第六版)》(23)(第十二章 类和动态内存分配 复习题和答案)
- 键盘控制移动
- 标准二维表问题
- 小白笔记------------------------leetcode(7. Reverse Integer)
- static
- 枚举类型-enum
- LeNet-5 理解
- 集合划分问题
- Windows系统下Android studio常用快捷键
- 用sublime还是用Eclipse自带编辑器?一张图看明白
- Java压缩和解压文件工具类ZipUtil
- LeetCode 477. Total Hamming Distance
- Kmeans算法与KNN算法的区别
- 封装框架(五)路由类