java编程思想 --19枚举类型

.在枚举中添加方法:
Java中的枚举是一种特殊的类,不但可以添加字段,构造方法,普通方法,甚至可以添加main()方法,例子如下:
public enum Test{
//调用枚举构造方法创建枚举对象
WEST(“Go west”), NORTH(“Go north”),
EAST(“Go east”), SOUTH(“Go south”);
private String description;
//私有构造方法
private Test(String description){
this.description = description;
}
public String getDescription(){
return description;
}
public static void main(String[] args){
for(Test witch : Test.values()){
System.out.println(witch + “: ” + witch.getDescription());
}
}
}
输出结果:
WEST:Go west
NORTH:Go north
EAST:Go east
SOUTH:Go south
注意:若要在枚举中定义字段和方法,必须在枚举对象的分号之后,java强制规定枚举对象必须放在枚举的最开始处。
另外,枚举的构造方法必须是private的,因为只允许在枚举内部定义枚举对象时使用,不允许在枚举类之后使用枚举的构造方法。
2.switch分支语句中使用枚举:
Java的switch分支语句中,switch的条件只能是整数数值类型,在JDK5以后枚举之后,由于枚举对象的顺序也是整数数值,因此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 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<5; i++){
System.out.println(t);
t.change();
}
}
}

输出结果:
The traffic light is RED
The traffic light is GREEN
The traffic light is YELLOW
The traffic light is RED
The traffic light is GREEN
3.枚举Set:
EnumSet枚举Set是JDK5中引入的与枚举类型一起使用的专用Set实现,EnumSet中所有键都必须来自单个枚举类型,枚举Set在内部表示为位向量。位向量表示形式的EnumSet非常紧凑高效,空间性和时间性非常好,同时由于枚举对象含义清楚,因此EnumSet可以替换传统技艺int的位标志(在程序开发中,很多时候需要使用一串数字序列的位标志,每位代表不同的含义,例如网络协议等)。例子如下:
//星期枚举
public enum Week{
MON, TUE, WEN, THU, FRI, SAT, SUN
}

import java.util.*;
//EnumSet例子
public class EnumSets{
public static void main(String[] args){
//EnumSet的noneOf方法创建指定枚举类型的空EnumSet
EnumSet<Week> weeks = EnumSet.noneOf(Week.class);
weeks.add(MON);
System.out.println(weeks);
//EnumSet的of方法创建包含指定枚举类型元素的EnumSet
weeks.addAll(EnumSet.of(TUE, WEN, THU));
System.out.println(weeks);
// EnumSet的allOf方法创建包含指定枚举类型所有元素的EnumSet
weeks = EnumSet.allOf(Week.class);
System.out.println(weeks);
weeks.removeAll(EnumSet.of(FRI, SAT, SUN));
System.out.println(weeks);
// EnumSet的rang方法创建包含指定枚举类型两个元素之间的EnumSet
weeks.removeAll(EnumSet.rang(MON, WEN));
System.out.println(weeks);
// EnumSet的complementOf方法创建指定EnumSet所不包含元素的EnumSet
weeks.removeAll(EnumSet.complementOf(weeks));
System.out.println(weeks);
}
}
输出结果:
[MON]
[MON, TUE, WEN, THU]
[MON, TUE, WEN, THU, FRI, SAT, SUN]
[MON, TUE, WEN, THU]
[THU]
[MON, TUE, WEN, FRI, SAT, SUN]
注意:EnumSet的元素排列是依据Enum的定义顺序排列的,所有的基本操作都在固定时间内执行,速度比HashSet可能更快。
4.枚举Map:
EnumMap是与枚举类型一起使用的专用Map实现,枚举Map中所有的键都必须来自单个枚举类型,枚举Map在内部表示为数组。和EnumSet类似,EnumMap键的顺序也是和Enum的定义顺序一致,EnumMap的所有操作也都在固定时间内执行,它的速度可能比HashMap更快。
下面的例子使用EnumMap演示command interface的设计模式:
public enum Directions{
EAST, NORTH, WEST, SOUTH
}
interface Command{
public void action();
}
public class EnumMaps{
Public static void main(String[] args){
EnumMap<Directions, Command> em =
new EnumMap<Directions, Command>(Directions.class);
em.put(EAST, new Command(){
public void action(){
System.out.println(“Go east”);
}
});
em.put(NORTH, new Command(){
public void action(){
System.out.println(“Go north”);
}
});
em.put(WEST, new Command(){
public void action(){
System.out.println(“Go west”);
}
});
for(Map.Entry<Directions, Command> e : em.entrySet()){
System.out.println(e.getKey() + “: ” + e.getValue().action());
}
try{
em.get(SOUTH).action();
}catch(Exception e){
System.out.println(e);
}
}
}

输出结果:
EAST: Go east
NORTH: Go north
WEST: Go west
java.lang.NullPointerException
从最后的空指针我们可以看出,EnumMap在创建时将Enum所有元素全部放进了key中,但是如果没有使用put显式将key和value关联的话,对应的value是null。
5.枚举特定方法:
在枚举中可以定义一个抽象的公共方法,然后各个枚举实例提供具体实现,实现一种类似匿名内部类的多态方式,例子如下:
import java.util.*;
import java.text.*;

public enum ConstantSpecificMethod{
DATE_TIME{
String getInfo(){
return DateFormat.getDateInstance().format(new Date());
}
},
CLASS_PATH{
String getInfo(){
return System.getenv(“CLASSPATH”);
}
},
VERSION{
String getInfo(){
return System.getProperty(“java.version”);
}
};
//抽象方法
abstract String getInfo();
public static void main(String[] args){
for(ConstantSpecificMethod csm : values()){
System.out.println(csm.getInfo());
}
}
}
通过这种多态方式,同样方便高效实现Commandinterface设计模式。

一、枚举简介:
为什么要用枚举:
枚举是Java1.5出来之后新增的类型,它可以用来定义一组取值范围固定的的变量。
在枚举没有出来之前,要定义这样的变量,往往是通过定义一个接口,将不同的变量
使用不同的整数赋值。但是这样的却有着很明显的缺点:
1.不能保证其定义数值的合法性;
枚举特性:
1.Enum类是枚举的一个封装类,,是所有枚举类型的超类,它是一个没有抽象方法的抽象类。
2.通过关键字"enum"可以定义枚举类型;
3.Enum类中定义了很多常用的方法:如元素间的比较,获取元素名称,获取元素定义的次序等:
a.compareTo(E o) : 比较枚举元素的顺序
b.equals(Object obj) : 判断枚举元素是否相同
c. name() : 获取元素定义时的名称
d.ordinal() : 获取枚举元素被定义时的顺序,从0开始计算
注:对于枚举可以使用"=="来比较两个枚举元素相同与否,由于他们已经自动了equals()和hashCode()两个方法,
故这两个方法不需要重写。
枚举的简单运用之创建和调用枚举:
1.枚举类的定义:
public enum Demo{
ENUMTYPEA,ENUMTYPEB,ENUMTYPEC;
}
2.在枚举类中,所有的属性以大写的形式存在,属性之间以逗号隔开,属性的值以括号String类型存在;
3.若是枚举属性有值strName,则需要定义这个strName,并且定义枚举类的有参构造方法,即必须要要先
定义枚举类型description才能定义构造方法Demo(String description);
public enum Demo{
ENUMTYPEA(strName),//枚举类型A,strName==" 枚举类型属性的值";
ENUMTYPEB(strName),//枚举类型B
ENUMTYPEC(strName);//枚举类型C
private String description;
private Demo(String description){
this.descrition = descrition;
}
public String getDescription(){
return description;
}
}
4.枚举类不能被继承,但可看作普通类,可重写方法,可有main方法。
5.枚举类的构造方法可以用public和protected修饰,但只能用来创建枚举对象,不能创建枚举类的实例
代码实例:
无参枚举类:
复制代码
package com.xhj.Enum;
/**
* 无参枚举
*
* @author XIEHEJUN
*
*/
public enum Color {
BLUE, YELLOW, RED, GREEN, WHITE, BRACK, PURPLE
}
复制代码
有参枚举类:
复制代码
package com.xhj.Enum;
/**
* 有参枚举
*
* @author XIEHEJUN
*
*/
public enum ColorValues {
BLUE("蓝色"), YELLOW("黄色"), RED("红色"), GREEN("绿色"), WHITE("白色"), BRACK("黑色"), PURPLE(
"紫色");
private String description;
private ColorValues(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
复制代码
枚举测试类:
复制代码
package com.xhj.Enum;
/**
* 对枚举封装类方法的简单运用
*
* @author XIEHEJUN
*
*/
public class Test {
/**
* 调用无参枚举
*/
public static void printColor() {
for (Color color : Color.values()) {
System.out.println("第" + (color.ordinal() + 1) + "个枚举是:"
+ color.name());
System.out
.println("此枚举和枚举BLUE比较的值为:" + color.compareTo(color.BLUE));
System.out.println("用&#39;equals()方法&#39;判断此枚举是否和枚举BLUE相等为:"
+ color.equals(color.BLUE));
System.out.println("用&#39;== &#39;的形式判断此枚举是否和枚举BLUE相等为:"
+ (color == color.BLUE));
System.out.println(color.getDeclaringClass());
System.out
.println("========================================================");
}
}
/**
* 调用有参枚举
*/
public static void printColorValues() {
for (ColorValues colorValues : ColorValues.values()) {
System.out.println("第" + (colorValues.ordinal() + 1) + "个枚举是:"
+ colorValues.name());
System.out.println("此枚举的值为:" + colorValues.getDescription());
System.out.println("此枚举和枚举BLUE比较的值为:"
+ colorValues.compareTo(colorValues.BLUE));
System.out.println("用&#39;equals()方法&#39;判断此枚举是否和枚举BLUE相等为:"
+ colorValues.equals(colorValues.BLUE));
System.out.println("用&#39;== &#39;的形式判断此枚举是否和枚举BLUE相等为:"
+ (colorValues == colorValues.BLUE));
System.out.println(colorValues.getDeclaringClass());
System.out
.println("========================================================");
}
}
public static void main(String[] args) {
Test
Test.printColor();
System.out
.println("***************************************************************\n"
+"***************************************************************");
Test.printColorValues();
}
}
复制代码
枚举的简单运用之switch调用枚举:
我们知道在java7(加上了switch可以调用String类型的特性)没有出来之前switch只能调用整数类型变量。
我想很多人可能会说,这个结论不对,因为他还可以调用枚举类型。
是的,没有错,switch确实可以调用枚举类型,但是她能调用的必要前提是调用的类型必须是整数。这个怎么理解呢?
其实,事实上是因为枚举类会自动的为它的每一个元素生成一个整数的顺序编号(可以通过ordinal()方法获知其编号),
所以当我们向switch传入枚举类型时,事实上,传进去的是一个整数--元素的顺序编号。
代码实例:
复制代码
package com.xhj.Enum;
/**
* switch枚举类型的调用
*
* @author XIEHEJUN
*
*/
public enum UseSwitch {
LILEI, LILY, SHITOU;
/**
* 获取每一个USER的性别
*
* @param user
* @return
*/
public static String getGrend(UseSwitch user) {
switch (user) {
case LILEI:
return "我是一名男孩";
case LILY:
return "我是一名女孩";
default:
return "咦?我是谁呢?";
}
}
public static void main(String[] args) {
for (UseSwitch user : UseSwitch.values()) {
System.out.println(user + ":" + user.getGrend(user));
}
}
}
复制代码
注:在switch语句中,若是有return返回值,则必须要有default语句:
二、枚举的高效运用:
枚举的高效运用之枚举集合:
Set回顾:
Set是Java集合类中一个很重要的子类,它用来存储不能重复的对象。
枚举和Set对比:
1.枚举也和Set一样要求每一个枚举元素都必须各不相同;
2.Set可以随意对数据进行增删操作,枚举不能。
EnumSet:
1.枚举集合,和Set集合一样,保证每一个元素的唯一性,不可重复性;
2.当创建EnumSet对象时,需要显式或隐士指明元素的枚举类型;
3.此对象中的元素仅能取自同一枚举类
4.在EnumSet内部以"位向量"的形式表示,这种结构紧凑而高效,使得类的时间、控件性能非常优越。
5.常用方法:
allOf(Class<E> elementType): 创建一个EnumSet,它包含了elementType 中所有枚举元素
complementOf(EnumSet<E> s): 创建一个EnumSet,其中的元素是s的补集
noneOf(Class<E> elementType): 创建一个EnumSet,其中的元素的类型是elementType,但是没有元素
range(E from, E to): 创建一个EnumSet,其中的元素在from和to之间,包括端点
add(E e): 增加一个元素e
remove(Object o): 删除一个元素o
addAll(Collection<? extends E>): 增加一个集合元素c
removeAll(Collection<?> c): 删除一集合元素c
注:不能在EnumSet中增加null元素,否则将会抛出空指针异常
代码实例:
复制代码
package com.xhj.Enum;
import java.util.EnumSet;
/**
* EnumSet的运用
*
* @author XIEHEJUN
*
*/
public class EnumSetDemo {
/**
* 获取元素信息并打印输出
*
* @param enumSet
*/
public static void getElement(EnumSet<ColorValues> enumSet) {
StringBuffer strName = new StringBuffer();
for (int j = 0; j < enumSet.size(); j++) {
System.out.print("\t" + enumSet.toArray()[j]);
for (ColorValues colorValues2 : enumSet) {
strName.append("\t" + colorValues2.getDescription() + "\n");
}
System.out.println(strName.toString().split("\n")[j]);
}
}
/**
* EnumSet方法的具体使用实例
*/
public static void getEnumSet() {
EnumSet<ColorValues> enumSet1 = EnumSet.allOf(ColorValues.class);
System.out.println("enumSet1枚举集合中元素有" + enumSet1.size() + "个");
System.out.println("分别是:");
getElement(enumSet1);
System.out
.println("=====================添加元素============================");
EnumSet<ColorValues> enumSet2 = EnumSet.noneOf(ColorValues.class);
System.out.println("\n此时枚举集合enumSet2中元素有" + enumSet2.size() + "个");
System.out.println("\n向枚举集合enumSet2添加一个元素" + ColorValues.BLUE);
enumSet2.add(ColorValues.BLUE);
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out.println("\n向枚举集合enumSet2添加一个元素" + ColorValues.RED);
enumSet2.add(ColorValues.RED);
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out.println("\n向枚举集合enumSet2添加一个元素" + ColorValues.GREEN);
enumSet2.add(ColorValues.GREEN);
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out.println("\n向枚举集合enumSet2添加ColorValues的补集enumSet3");
EnumSet<ColorValues> enumSet3 = EnumSet.complementOf(enumSet2);
getElement(enumSet3);
enumSet2.addAll(enumSet3);
System.out.println("\n此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out
.println("=====================删除元素============================");
System.out.println("\n枚举集合enumSet2删除一个元素" + ColorValues.GREEN);
enumSet2.remove(ColorValues.GREEN);
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out.println("\n枚举集合enumSet2删除一个固定范围内的元素");
enumSet2.removeAll(enumSet2
.range(ColorValues.YELLOW, ColorValues.WHITE));
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out.println("\n枚举集合enumSet2删除一个枚举集合enumSet3,这个集合的元素个数有:"
+ enumSet3.size());
enumSet2.removeAll(enumSet3);
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
getElement(enumSet2);
System.out
.println("=====================清除所有元素============================");
enumSet2.clear();
System.out.println("此时枚举集合enumSet2中元素个数有:" + enumSet2.size());
}
public static void main(String[] args) {
EnumSetDemo.getEnumSet();
}
}
复制代码
枚举的高效运用之枚举映射:
1.对于枚举集合来说,Java除了提供EnumSet外,还提供了另外一个集合类EnumMap
2.Map是Java集合类的子类,主要是通过键值对来保存对象,要求其键必须是唯一的;
3.在枚举类型中,枚举元素也是要求唯一的,固可作为Map的键。
4.EnumMap类是Java专门为枚举类型提供的Map实现类。
5.和EnumSet类一样,当创建EnumMap类型时,要显式或者隐式指明其元素的枚举类型,且只能取自统一枚举类
6.在EunmMap内部,用数组表示
7.常用方法:
clear(): 删除所有映射关系
containKey(Object key): 若包含此key,则返回true,否则返回false
containsValue(Object value): 若包含此value,则返回true,否者返回false
put(K key,V value): 往EnumMap中存入键值对
get(Object key): 获取键为key对应的value值
size(): 查看EnumMap中键值对的个数
remove(Object key): 删除键为key相对应的value值
注:在EunmMap中,不可存入null,否则将抛出空指针异常
代码实例:
复制代码
package com.xhj.Enum;
import java.util.EnumMap;
/**
* EnumMap的运用
*
* @author XIEHEJUN
*
*/
public class EnumMapDemo {
/**
* EnumMap的具体运用
*/
public static void getEnumMap() {
EnumMap<ColorValues, String> enumMap1 = new EnumMap<ColorValues, String>(
ColorValues.class);
String[] Weeks = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天" };
System.out
.println("==========================添加枚举键值对================================");
enumMap1.put(ColorValues.BLUE, ColorValues.BLUE.getDescription()
+ Weeks[ColorValues.BLUE.ordinal()]);
System.out.println("key=0时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
enumMap1.put(ColorValues.BRACK, ColorValues.BRACK.getDescription()
+ Weeks[ColorValues.BRACK.ordinal()]);
System.out.println("key=1时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
enumMap1.put(ColorValues.GREEN, ColorValues.GREEN.getDescription()
+ Weeks[ColorValues.GREEN.ordinal()]);
System.out.println("key=2时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
enumMap1.put(ColorValues.PURPLE, ColorValues.PURPLE.getDescription()
+ Weeks[ColorValues.PURPLE.ordinal()]);
System.out.println("key=3时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
enumMap1.put(ColorValues.RED, ColorValues.RED.getDescription()
+ Weeks[ColorValues.RED.ordinal()]);
System.out.println("key=4时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
enumMap1.put(ColorValues.WHITE, ColorValues.WHITE.getDescription()
+ Weeks[ColorValues.WHITE.ordinal()]);
System.out.println("key=5时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
enumMap1.put(ColorValues.YELLOW, ColorValues.YELLOW.getDescription()
+ Weeks[ColorValues.YELLOW.ordinal()]);
System.out.println("key=6时enumMap1的元素有 " + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
System.out
.println("==========================判断枚举键值对================================");
System.out.println("判断是否存在键" + ColorValues.BLUE);
System.out.println("结果为:" + enumMap1.containsKey(ColorValues.BLUE));
System.out.println("判断是否存在值&#39;蓝色星期二&#39;");
System.out.println("结果为:" + enumMap1.containsValue("蓝色星期二"));
System.out
.println("==========================删除枚举键值对================================");
enumMap1.remove(ColorValues.BLUE);
System.out.println("剩余元素有:" + enumMap1);
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
System.out
.println("==========================获取键对应的值================================");
System.out.println(" 获取RED对应的值,结果为: " + enumMap1.get(ColorValues.RED));
System.out
.println("==========================清空枚举键值对================================");
enumMap1.clear();
System.out.println(" 此时键值对个数为: " + enumMap1.size() + "\n");
}
public static void main(String[] args) {
getEnumMap();
}
}
复制代码
注:EnumMap可以用来实现23种设计模式中的命令模式(对于设计模式,后续会有详细的笔记)
枚举的高效运用之遍历枚举接口元素:
1.集合类的主要作用就是用来管理一组相关的对象,当需要查看、使用集合中的所有对象时可以使用枚举接口对其进行遍历。
2.实现了Enumeration接口的对象可以生成一系列元素,每次生成一个。
3.通过连续调用nextElement()方法可以连续获得枚举接口中的元素。但若枚举接口已没有元素,调用该方法会抛出异常。
故在这之前要先用hasMoreElement()进行判断:
boolean hasMoreElements()
4.Collection类的静态方法enumeration()可以用来将任意集合转换成枚举接口类型。
代码实例:
复制代码
package com.xhj.Enum;
import java.util.Enumeration;
import java.util.Vector;
/**
* 使用枚举接口遍历集合对象
*
* @author XIEHEJUN
*
*/
public class ErgodicEnumInterface {
public static void main(String[] args) {
Vector<String> vector = new Vector<String>();
vector.add("您好!");
vector.add("很高兴见到你!");
vector.add("我是和佑");
Enumeration<String> e = vector.elements();
while (e.hasMoreElements()) {
System.out.println(e.nextElement());
}
}
}
复制代码
注:在实际项目中,如果要遍历集合对象,我们一般使用Iterator()接口来实现。
在Iterator接口中主要方法有:
hasNext(): 判断是否还有可用元素;
next(): 获取元素;
remove()删除元素;
枚举的高效运用之实现简单文件合并:
1.SequenceInputStream 类可以用来接收元素类型为输入流的枚举接口类型。
2.SequenceInputStream类表示其他类型的输入流的逻辑组合。
3.在创建这个类的对象时需要指定一组有序的输入流集合。
4,要实现合并多个文件,需要使用Enumeration类型作为方法的参数。
SequenceInputStream(Enumeration<? extends InputStream> e)
e:包含若干个输入流的枚举接口类型的对象。
注:使用泛型可以避免为枚举接口传入不同的类型。
5.注意:在绝对路径中需要指明文件的扩展名,否则生成的文件就有了类型
代码实例1:
不用SequenceInputStream实现
复制代码
package com.xhj.io;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
/**
* 利用SequenceInputStream方法合并文件
*
* @author XIEHEJUN
*
*/
public class MergeFiles {
public static File createFile(String uri, String contents) {
File file = new File(uri);
try {
OutputStream os = new FileOutputStream(uri);
os.write(contents.getBytes());
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return file;
}
public static String getContents(File file) {
StringBuffer sb = new StringBuffer();
try {
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
BufferedReader b_reader = new BufferedReader(
new InputStreamReader(is));
String inLine = b_reader.readLine();
while (inLine != null) {
// System.getProperty("line.separator")--获取当前系统的换行符
sb.append(inLine + System.getProperty("line.separator"));
inLine = b_reader.readLine();
}
b_reader.close();
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
public static void main(String[] args) {
File file1 = createFile("src/com/xhj/io/file1.txt", "你好!");
File file2 = createFile("src/com/xhj/io/file2.txt", "你好!我是和佑!");
File file3 = createFile("src/com/xhj/io/file3.txt", "你呢?");
String content1 = mergeContents(getContents(file1), getContents(file2));
String content2 = mergeContents(content1, getContents(file3));
createFile("src/com/xhj/io/file3.txt", content2);
}
/**
* 合并内容
*
* @param contents1
* @param contents2
* @return
*/
public static String mergeContents(String contents1, String contents2) {
contents1 = contents1.replace("\r\n", "");
if (contents2.indexOf(contents1) == -1) {
contents2 = contents1 + contents2;
}
return contents2;
}
}

枚举其实就是一种类型,跟int, char 这种差不多,就是定义变量时限制输入的,你只能够赋enum里面规定的值。建议大家可以看看,这两篇文章,《java枚举类型入门》和《C++的中的结构体和枚举》,供大家参考。
枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字enum来定义一个枚举类。下面就是一个典型枚举类型的定义:
Java代码:
public enum Color{  
RED,BLUE,BLACK,YELLOW,GREEN  

 
显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类。 而这些类都是类库中Enum类的子类(java.lang.Enum)。它们继承了这个Enum中的许多有用的方法。我们对代码编译之后发现,编译器将enum类型单独编译成了一个字节码文件:Color.class。
Color字节码代码
final enum hr.test.Color {  
// 所有的枚举值都是类静态常量  
public static final enum hr.test.Color RED;  
public static final enum hr.test.Color BLUE;  
public static final enum hr.test.Color BLACK;  
public static final enum hr.test.Color YELLOW;  
public static final enum hr.test.Color GREEN;  
private static final synthetic hr.test.Color[] ENUM$VALUES;  
// 初始化过程,对枚举类的所有枚举值对象进行第一次初始化  
static {  
0 new hr.test.Color [1]  
3 dup  
4 ldc [16] //把枚举值字符串“RED”压入操作数栈  
6 iconst_0 // 把整型值0压入操作数栈  
7 invokespecial hr.test.Color(java.lang.String, int) [17] //调用Color类的私有构造器创建Color对象RED  
10 putstatic hr.test.Color.RED : hr.test.Color [21] //将枚举对象赋给Color的静态常量RED。  
。..。..。.. 枚举对象BLUE等与上同  
102 return 
};  
// 私有构造器,外部不可能动态创建一个枚举类对象(也就是不可能动态创建一个枚举值)。  
private Color(java.lang.String arg0, int arg1){  
// 调用父类Enum的受保护构造器创建一个枚举对象  
3 invokespecial java.lang.Enum(java.lang.String, int) [38]  
};  
public static hr.test.Color[] values();  
// 实现Enum类的抽象方法  
public static hr.test.Color valueOf(java.lang.String arg0);  

 
下面我们就详细介绍enum定义的枚举类的特征及其用法。(后面均用Color举例)
1、Color枚举类就是class,而且是一个不可以被继承的final类。
其枚举值(RED,BLUE.。.)都是Color类型的类静态常量, 我们可以通过下面的方式来得到Color枚举类的一个实例:
Color c=Color.RED; 
 
注意:这些枚举值都是public static final的,也就是我们经常所定义的常量方式,因此枚举类中的枚举值最好全部大写。
2、即然枚举类是class,当然在枚举类型中有构造器,方法和数据域。
但是,枚举类的构造器有很大的不同:
(1) 构造器只是在构造枚举值的时候被调用。
Java代码:
enum Color{  
RED(255,0,0),BLUE(0,0,255),BLACK(0,0,0),YELLOW(255,255,0),GREEN(0,255,0);  
//构造枚举值,比如RED(255,0,0)  
private Color(int rv,int gv,int bv){  
this.redValue=rv;  
this.greenValue=gv;  
this.blueValue=bv;  
}  
public String toString(){ //覆盖了父类Enum的toString()  
return super.toString()+“(”+redValue+“,”+greenValue+“,”+blueValue+“)”;  
}  
private int redValue; //自定义数据域,private为了封装。  
private int greenValue;  
private int blueValue;  

(2) 构造器只能私有private,绝对不允许有public构造器。 这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据域可以允许外部访问。
Java代码:
public static void main(String args[])  
{  
// Color colors=new Color(100,200,300); //wrong  
Color color=Color.RED;  
System.out.println(color); // 调用了toString()方法  

 
3、所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。
(1) ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
Color.RED.ordinal(); //返回结果:0  
Color.BLUE.ordinal(); //返回结果:1 
 
(2) compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。(具体可见源代码)
Color.RED.compareTo(Color.BLUE); //返回结果 -1 
 
(3) values()方法: 静态方法,返回一个包含全部枚举值的数组。
Color[] colors=Color.values();  
for(Color c:colors){  
System.out.print(c+“,”);  
}//返回结果:RED,BLUE,BLACK YELLOW,GREEN, 
 
(4) toString()方法: 返回枚举常量的名称。
Color c=Color.RED;  
System.out.println(c);//返回结果: RED 
 
(5) valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
Color.valueOf(“BLUE”); //返回结果: Color.BLUE 
 
(6) equals()方法: 比较两个枚举类对象的引用。
Java代码:
//JDK源代码:  
public final boolean equals(Object other) {  
return this==other;  

4、枚举类可以在switch语句中使用。
Java代码:
Color color=Color.RED;  
switch(color){  
case RED: System.out.println(“it‘s red”);break;  
case BLUE: System.out.println(“it’s blue”);break;  
case BLACK: System.out.println(“it‘s blue”);break;  

希望通过本文对java中枚举的介绍,能够给你到来帮助。


枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字enum来定义一个枚举类。下面就是一个典型枚举类型的定义:
Java代码  
public enum Color{  
    RED,BLUE,BLACK,YELLOW,GREEN  
}  
显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类。 而这些类都是类库中Enum类的子类(java.lang.Enum<E>)。它们继承了这个Enum中的许多有用的方法。我们对代码编译之后发现,编译器将enum类型单独编译成了一个字节码文件:Color.class。
Color字节码代码  
final enum hr.test.Color {  
    
 // 所有的枚举值都是类静态常量  
 public static final enum hr.test.Color RED;  
 public static final enum hr.test.Color BLUE;  
 public static final enum hr.test.Color BLACK;  
 public static final enum hr.test.Color YELLOW;  
 public static final enum hr.test.Color GREEN;  
   
private static final synthetic hr.test.Color[] ENUM$VALUES;  
    
  // 初始化过程,对枚举类的所有枚举值对象进行第一次初始化  
 static {  
       0  new hr.test.Color [1]   
      3  dup  
      4  ldc <String "RED"> [16] //把枚举值字符串"RED"压入操作数栈  
      6  iconst_0  // 把整型值0压入操作数栈  
      7  invokespecial hr.test.Color(java.lang.String, int) [17] //调用Color类的私有构造器创建Color对象RED  
     10  putstatic hr.test.Color.RED : hr.test.Color [21]  //将枚举对象赋给Color的静态常量RED。  
      .........  枚举对象BLUE等与上同  
    102  return  
};  
    
  // 私有构造器,外部不可能动态创建一个枚举类对象(也就是不可能动态创建一个枚举值)。  
 private Color(java.lang.String arg0, int arg1){  
     // 调用父类Enum的受保护构造器创建一个枚举对象  
     3  invokespecial java.lang.Enum(java.lang.String, int) [38]  
};  
   
 public static hr.test.Color[] values();  
    
   // 实现Enum类的抽象方法    
  public static hr.test.Color valueOf(java.lang.String arg0);  
}  
 
下面我们就详细介绍enum定义的枚举类的特征及其用法。(后面均用Color举例)

1、Color枚举类就是class,而且是一个不可以被继承的final类。其枚举值(RED,BLUE...)都是Color类型的类静态常量, 我们可以通过下面的方式来得到Color枚举类的一个实例:
                                                         Color c=Color.RED;
注意:这些枚举值都是public static final的,也就是我们经常所定义的常量方式,因此枚举类中的枚举值最好全部大写。

2、即然枚举类是class,当然在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同:
      (1) 构造器只是在构造枚举值的时候被调用。
Java代码  
enum Color{  
                RED(255,0,0),BLUE(0,0,255),BLACK(0,0,0),YELLOW(255,255,0),GREEN(0,255,0);  
                //构造枚举值,比如RED(255,0,0)  
                private Color(int rv,int gv,int bv){  
                 this.redValue=rv;  
                 this.greenValue=gv;  
                 this.blueValue=bv;  
                }  
  
                public String toString(){  //覆盖了父类Enum的toString()  
                return super.toString()+"("+redValue+","+greenValue+","+blueValue+")";  
                }  
     
                private int redValue;  //自定义数据域,private为了封装。  
                private int greenValue;  
                private int blueValue;  
 }  
      (2) 构造器只能私有private,绝对不允许有public构造器。 这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据域可以允许外部访问。
Java代码  
public static void main(String args[])  
{  
        // Color colors=new Color(100,200,300);  //wrong  
           Color color=Color.RED;  
           System.out.println(color);  // 调用了toString()方法  
}     
 
3、所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。
       (1)  ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
                 Color.RED.ordinal();  //返回结果:0
                 Color.BLUE.ordinal();  //返回结果:1
       (2)  compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。(具体可见源代码)
                 Color.RED.compareTo(Color.BLUE);  //返回结果 -1
       (3)  values()方法: 静态方法,返回一个包含全部枚举值的数组。
                 Color[] colors=Color.values();
                 for(Color c:colors){
                        System.out.print(c+",");
                 }//返回结果:RED,BLUE,BLACK YELLOW,GREEN,
       (4)  toString()方法: 返回枚举常量的名称。
                 Color c=Color.RED;
                 System.out.println(c);//返回结果: RED
       (5)  valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
                 Color.valueOf("BLUE");   //返回结果: Color.BLUE
       (6)  equals()方法: 比较两个枚举类对象的引用。
Java代码  
//JDK源代码:      
public final boolean equals(Object other) {  
        return this==other;  
}               

4、枚举类可以在switch语句中使用。
Java代码  
Color color=Color.RED;  
switch(color){  
        case RED: System.out.println("it's red");break;  
        case BLUE: System.out.println("it's blue");break;  
        case BLACK: System.out.println("it's blue");break;  
}  

在任何集合类中,必须通过某种方法在其中置入对象,再用另一种方法从中取得对象。
毕竟,容纳各种各样的对象正是集合的首要任务。在Vector 中,addElement()便是我们插入对象采用的方法,而elementAt()是提取对象的唯一方法。Vector 非常灵活,我们可在任何时候选择任何东西,并可使用不同的索引选择多个元素。
若从更高的角度看这个问题,就会发现它的一个缺陷:需要事先知道集合的准确类型,否则无法使用。乍看来,这一点似乎没什么关系。但假若最开始决定使用Vector,后来在程序中又决定(考虑执行效率的原因)改变成一个List(属于Java1.2 集合库的一部分),这时又该如何做呢?
可利用“反复器”(Iterator)的概念达到这个目的。它可以是一个对象,作用是遍历一系列对象,并选择那个序列中的每个对象,同时不让客户程序员知道或关注那个序列的基础结构。此外,我们通常认为反复器是一种“轻量级”对象;也就是说,创建它只需付出极少的代价。但也正是由于这个原因,我们常发现反复器存在一些似乎很奇怪的限制。例如,有些反复器只能朝一个方向移动。Java 的Enumeration(枚举)便是具有这些限制的一个反复器的例子。除下面这些外,不可再用它做其他任何事情:
(1) 用一个名为elements()的方法要求集合为我们提供一个Enumeration。我们首次调用它的nextElement()时,这个Enumeration 会返回序列中的第一个元素。
(2) 用nextElement() 获得下一个对象。
(3) 用hasMoreElements()检查序列中是否还有更多的对象。
只可用Enumeration 做这些事情,不能再有更多。它属于反复器一种简单的实现方式,但功能依然十分强大。
1      示例1
import java.util.*;
 
class Cat2 {
    privateintcatNumber;
    Cat2(inti) {
        catNumber =i;
    }
    void print() {
        System.out.println("Cat number " +catNumber);
    }
}
class Dog2 {
    privateintdogNumber;
    Dog2(inti) {
        dogNumber =i;
    }
    void print() {
        System.out.println("Dog number " +dogNumber);
    }
}
publicclass CatsAndDogs2 {
    publicstaticvoidmain(String[]args){
        Vector cats = new Vector();
        for (inti = 0; i < 7;i++)
            cats.addElement(new Cat2(i));
        // Not a problem to add a dog to cats:
        cats.addElement(new Dog2(7));
        Enumeration e = cats.elements();
        while (e.hasMoreElements())
            ((Cat2) e.nextElement()).print();
        // Dog is detected only at run-time
    }
}
2      输出
Catnumber 0
Catnumber 1
Catnumber 2
Catnumber 3
Catnumber 4
Catnumber 5
Catnumber 6
Exceptionin thread "main"java.lang.ClassCastException: Dog2 cannot be cast to Cat2
    at CatsAndDogs2.main(CatsAndDogs2.java:36)
3      常规用途的打印方法
// Using an Enumeration
import java.util.*;
class Hamster {
    privateinthamsterNumber;
    Hamster(inti) {
        hamsterNumber =i;
    }
    public String toString() {
        return"This is Hamster #" + hamsterNumber;
    }
}
class Printer {
    staticvoidprintAll(Enumeration e) {
        while (e.hasMoreElements())
            System.out.println(e.nextElement().toString());
    }
}
publicclass HamsterMaze {
    publicstaticvoidmain(String[]args){
        Vector v = new Vector();
        for (inti = 0; i < 3;i++)
            v.addElement(new Hamster(i));
        Printer.printAll(v.elements());
    }
}
4      输出2:
Thisis Hamster #0
Thisis Hamster #1
This is Hamster #2
其中没有与序列类型有关的信息。我们拥有的全部东西便是Enumeration。为了解有关序列的情况,一个Enumeration 便足够了:可取得下一个对象,亦可知道是否已抵达了末尾。取得一系列对象,然后在其中遍历,从而执行一个特定的操作——这是一个颇有价值的编程概念.
调用打印的另一个方法(尽管在效率上可能会差一些):
System.out.println(""+ e.nextElement());
它采用了封装到Java 内部的“自动转换成字串”技术。一旦编译器碰到一个字串,后面跟随一个“+”,就会希望后面又跟随一个字串,并自动调用toString()。在Java 1.1 中,第一个字串是不必要的;所有对象都会转换成字串。亦可对此执行一次造型,获得与调用toString()同样的效果:
System.out.println((String)e.nextElement())
但我们想做的事情通常并不仅仅是调用Object 方法,所以会再度面临类型造型的问题。对于自己感兴趣的类型,必须假定自己已获得了一个Enumeration,然后将结果对象造型成为那种类型(若操作错误,会得到运行期违例)。

关键字enum可以将一组具名的值有限集合创建一种为新的类型,而这些具名的值可以作为常规的程序组件使用。

基本enum特性
调用enum的values()方法可以遍历enum实例,values()方法返回enum实例数组,且数组中元素保持在enum声明时的顺序。


1 public class TestEnum {
2     public static void main(String[] args) {
3         Fruit[] values = Fruit.values();
4         for (Fruit fruit : values) {
5             System.out.println(fruit);
6             printEnum(fruit);
7         }
8     }
9
10     public enum Fruit {
11         APPLE, ORANGE, WATERMELON
12     }
13
14    public static void printEnum(Fruit fruit) {
15         //顺序
16         System.out.println(fruit + " ordinal:" + fruit.ordinal());
17         //比较(ordinal值)
18         System.out.println("compare to apple" + fruit.compareTo(Fruit.APPLE));
19         //==
20         System.out.println(fruit == Fruit.ORANGE);
21         //获取所属的enum类
22         System.out.println(fruit.getDeclaringClass());
23         //获取名字
24         System.out.println(fruit.name());
25     }
26 }
27
28 //output
29 /**
30 APPLE
31 ORANGE
32 WATERMELON
33 */
34
35 /**
36 APPLE ordinal:0
37 compare to apple0
38 false
39 class com.TestEnum$Fruit
40 APPLE
41 ORANGE ordinal:1
42 compare to apple1
43 true
44 class com.TestEnum$Fruit
45 ORANGE
46 WATERMELON ordinal:2
47 compare to apple2
48 false
49 class com.TestEnum$Fruit
50 WATERMELON
51 */

ordinal()方法返回int值:表示enum实例在声明时的次序,从0开始。
使用==来比较enum实例。

将静态导入用于enum
使用static import能够将enum实例的标识符带入当前命名空间,无需再用emum类型来修饰enum实例。
import static----> MALE
import----> Gender.MALE


1 package com;
2
3 import static com.Gender.*;
4
5 /**
6  * Created by JohnTsai on 15/10/22.
7  */
8 public class TestStaticImport {
9     Gender gender;
10
11     public static void main(String[] args) {
12         System.out.println(new TestStaticImport(MALE));
13         System.out.println(new TestStaticImport(FEMALE));
14     }
15
16     public TestStaticImport(Gender gender) {
17         this.gender = gender;
18     }
19
20     @Override
21     public String toString() {
22         return "GENDER is" + this.gender;
23     }
24 }

enum中的构造器与方法和普通的类没有区别,除了少数限制外,enum就是一个普通的类。(一般只使用普通的枚举类型)
需先定义enum实例,然后再定义自己的方法。


1 package com;
2
3 /**
4  * Created by JohnTsai on 15/10/23.
5  */
6 public enum Direction {
7     //最先定义enum实例
8     WEST("this is west"),EAST("this is east"),NORTH("this is north"),SOUTH("this is south");
9     //要定义自己的方法,需在定义的enum实例后加分号
10
11     private String text;
12     private Direction(String text){
13         this.text = text;
14     }
15     public String getText(){
16         return this.text;
17     }
18
19     public static void main(String[] args) {
20         for(Direction direction:Direction.values()){
21             System.out.println(direction+":"+direction.getText());
22         }
23     }
24
25 }

覆盖enum的方法
覆盖enum的toString()方法和覆盖一般类的方法没有区别。

switch语句中的enum
enum提供了非常便利的功能:在switch中使用enum。


1 package com;
2
3 /**
4  * Created by JohnTsai on 15/10/23.
5  */
6 enum Signal {
7     GREEN, YELLOW, RED
8 }
9
10 public class TrafficLight {
11     Signal color = Signal.GREEN;
12
13     public void change() {
14         switch (color) {
15             case RED:
16                 color = Signal.GREEN;
17                 break;
18             case GREEN:
19                 color = Signal.YELLOW;
20                 break;
21             case YELLOW:
22                 color = Signal.RED;
23                 break;
24         }
25     }
26
27     @Override
28     public String toString() {
29         return "traffic light is" + color;
30     }
31
32     public static void main(String[] args) {
33         TrafficLight light = new TrafficLight();
34         for (int i = 0; i < 10; i++) {
35             System.out.println(light);
36             light.change();
37         }
38     }
39 }

values()的神秘之处
编译器为我们创建的enum类都继承自Enum类。
但是Enum类中并没有values()方法。


1 package com;
2
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Type;
5 import java.util.Set;
6 import java.util.TreeSet;
7
8 /**
9  * Created by JohnTsai on 15/10/25.
10  */
11 enum Explore{
12     HERE,THERE
13 }
14 public class Reflection {
15     public static Set<String> analyse(Class<?> enumClass){
16         println("Analyzing begin:");
17         println("Interfaces:");
18         for(Type t:enumClass.getGenericInterfaces()){
19             print(t.toString());
20         }
21         println("Base:"+enumClass.getSuperclass());
22         println("Methods:");
23         Set<String> methods = new TreeSet<>();
24         for(Method m:enumClass.getMethods()){
25             methods.add(m.getName());
26         }
27         println(methods.toString());
28         return methods;
29     }
30
31
32     public static void println(String s){
33         System.out.println(s);
34     }
35
36     public static void print(String s){
37         System.out.print(s);
38     }
39
40     public static void main(String[] args) {
41         Set<String> exploreMethods = analyse(Explore.class);
42         Set<String> enumMethods = analyse(Enum.class);
43         println("Explore containsAll(Enum)?"+exploreMethods.containsAll(enumMethods));
44         println("Explore removeAll(Enum)"+exploreMethods.removeAll(enumMethods));
45
46         println(exploreMethods.toString());
47     }
48 }
49
50
51 //output:
52 /**Analyzing begin:
53 Interfaces:
54 Base:class java.lang.Enum
55 Methods:
56 [compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait]
57 Analyzing begin:
58 Interfaces:
59 java.lang.Comparable<E>interface java.io.SerializableBase:class java.lang.Object
60 Methods:
61 [compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait]
62 Explore containsAll(Enum)?true
63 Explore removeAll(Enum)true
64 [values]
65 */

反编译之前的枚举类型Gender

javac Gender.class
javap Gender
Compiled from "Gender.java"
public final class com.Gender extends java.lang.Enum<com.Gender> {
  public static final com.Gender MALE;
  public static final com.Gender FEMALE;
  public static com.Gender[] values();
  public static com.Gender valueOf(java.lang.String);
  static {};
}
values()是由编译器添加的static方法。编译器还添加了valueOf()方法。
添加的这个valueOf()方法和Enum中的valueOf()方法不同。前者只有一个参数而后者有两个。

由于values()方法是由编译器插入到enum定义的static方法,当enum实例向上转型为Enum,values()方法就不能调用了。
Class中有个getEnumConstants()方法可以获取到所有enum实例。


1 package com;
2
3 /**
4  * Created by JohnTsai on 15/10/25.
5  */
6 public class UpcastEnum {
7     public static void main(String[] args) {
8         Gender[] values = Gender.values();
9         Enum e = Gender.MALE;
10 //        e.values();No values() in Enum
11         for (Enum en : e.getClass().getEnumConstants()) {
12             System.out.println(en);
13         }
14     }
15 }
16
17 //output
18 /**
19 MALE
20 FEMALE
21 */

实现,而非继承
所有的enum都继承自java.lang.Enum类。

1  System.out.println("Gender's super class:"+Gender.class.getSuperclass());
2 //output:
3 //Gender's super class:class java.lang.Enum
由于java不支持多继承,所以enum不能再继承其他类了。然而,我们可以在创建一个新的enum时,可以同时实现一个或多个接口。













猜你喜欢

转载自zhyp29.iteye.com/blog/2307487