黑马程序员——Java 枚举

------- android培训java培训、期待与您交流! ----------

 

Java枚举

 

枚举是限定有限可能值的一种手段,使用枚举可以降低程序出错的几率,并可以提高代码的可读性与可维护性。Java中的枚举并不是简单常量的集合,而是一个对象,其本质依然是类,所以Java中的枚举除了提供一系列相关值以外,还提供了一些额外功能,甚至还可以根据需要自行添加一些功能。

1. 使用简单程序完成枚举的功能

枚举是JDK5.0之后引入的,如果在JDK5.0之前完成枚举的功能,则必须依靠类似下面示例程序代码完成。

/**
 * @desc 实现枚举类似的功能 
 */
public class Color {

	private static final Color RED = new Color("红色");
	private static final Color GREEN = new Color("绿色");
	private static final Color BLUE = new Color("蓝色");
	private String name ;

	public Color(String color) {
		this.name = color;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = 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 static void main(String[] args) {
		Color c1 = Color.RED;
		System.out.println(c1.getName());//红色
		Color c2 = Color.getInstance(3);
		System.out.println(c2.getName());//蓝色
	}
}

在上面程序将Color类中的构造方法私有化,之后在类中准备了若干个实例化对象,以后如果要取得Color类的实例,则只能从RED、GREEN、BLUE3个对象中取得,这样就有效地限制了对象的取得范围。

以上使用Color对象指定的范围,是通过一个个常量对每个对象进行编号的。也就是说,一个个的对象就相当于用常量表示了,所以,按照这个思路也可以直接使用一个接口规定出一组常量的范围。

public interface Color {
	public static final int RED = 1;
	public static final int GREEN = 2;
	public static final int BLUE = 3;
}

虽然与之前比更加简单,但是也会存在一些问题。比如说

Color.RED + Color.BLUE

两种颜色的常量相加之后形成了“4”,这样的结果让人看起来很困惑,操作很不明确。

2. 定义枚举

2.1 定义枚举

 

定义枚举需要使用关键字enum。例如一个应用需要使用一系列特定的颜色值,则可以定义一个类似以下形式的枚举。

public enum MyColor {
	RED,BLUE,GREEN
}

实际上,这个声明定义的类型是一个类,它刚好有3个实例,在此尽量不要构造新对象。

2.2 使用枚举

枚举定义完成以后,就可以以枚举名.枚举项的形式在代码中对定义的枚举进行使用。在特殊情况下,如果程序能够识别出当前的枚举类型,则只需要给出枚举项即可,例如在switch语句块中的case关键字后的常量值。以下是一段使用枚举的简单示例代码。

MyColor c =  MyColor.RED;
switch(c)
{
	case RED:
	    System.out.println("红色");
	    break;
	case BLUE:
	    System.out.println("蓝色");
	    break;
	case GREEN:
	    System.out.println("绿色");
	    break;
	default:
	    System.out.println("未知色");
	    break;
}

2.3 常规方法

Java枚举提供了几个方法供开发者在需要时调用,对于枚举对象,主要可用的方法为values,它返回当前枚举中定义的所有枚举项的集合;对于枚举项,主要可用的方法有ordinalnamegetDeclaringClass。方法ordinal返回枚举项在枚举对象中的序号;方法name则返回枚举项的名称(与方法toString效果相同),通常用于取得枚举变量中保存的枚举项名称;而方法getDeclaringClass则用于取得当前枚举值所在类的完整名称。

此外,枚举项之间还可以通过方法compareTo进行比较,如果参数传入的枚举项与当前值相等,则返回0

enum MyColor {
	RED, BLUE, GREEN
}

public class EnumExample {
	public static void main(String[] args) {
		MyColor color0 = MyColor.RED;
		switch(color0){
		case RED:
			System.out.println("红色");
			break;
		case BLUE:
			System.out.println("蓝色");
			break;
		case GREEN:
			System.out.println("绿色");
			break;
		default:
			System.out.println("error");
			break;
		}
		for(MyColor myColor : MyColor.values()) {
			System.out.println(myColor);
			System.out.println(myColor.ordinal());
			System.out.println(myColor.name());
			System.out.println(myColor.getDeclaringClass());
			System.out.println("===========================");
		}
		MyColor color1 = MyColor.valueOf("RED");
		System.out.println(color1);
		System.out.println(color1.ordinal());
		System.out.println(color1.name());
		System.out.println(color1.getDeclaringClass());
	}
}

 

3. 枚举的构造器、方法或域

 

3.1 构造方法

 

类拥有构造器,枚举是一种特殊的类,所以枚举也可以拥有自己的构造器。但与普通类的不同之处在于枚举的构造器不可以是public的,其原因在于该构造器是提供给枚举对象中的枚举项构造时使用的,它并不需要在枚举对象之外使用。

例如,如果希望枚举MyColor中的每个枚举项包含有相应的中文说明以及其对应的Color信息,则可以为MyColor增加一个包含有两个参数的构造器,并且在声明每一个枚举项时使用这个构造器进行构造。其实现代码如下:

enum MyColor{
    RED("红色",Color.RED),
    BLUE("蓝色",Color.BLUE),
    GREEN("绿色",Color.GREEN);

    private String summy;
    private Color color;

    private MyColor(Stringsummy, Color color){
        this.summy = summy;
        this.color = color;
    }
}

 

3.2 成员方法

 

如同可以为枚举添加构造器一样也可以为枚举添加方法。例如上述代码中通过构造器为每个枚举项添加了中文说明以及其对应的Color信息,那么为了取出枚举项对应的信息,则需要为枚举MyColor添加如下相应方法。

public String getSummy(){
    return this.summy;
}
public Color getColor(){
    return this.color;
}

可以看到,通过以上机制,可以将枚举本身要表达的含义与其具体的信息很好地整合起来,杜绝了传统编程语言中含义与信息分离的弊端。

枚举构造器、成员方面及完整的测试代码如下:

import java.awt.Color;
enum MyColor {
	RED("红色", Color.RED), 
	BLUE("蓝色", Color.BLUE), 
	GREEN("绿色", Color.GREEN);

	private String summy;
	private Color color;
	private MyColor(String summy, Color color) {
		this.summy = summy;
		this.color = color;
	}
	public String getSummy() {
		return this.summy;
	}
	public Color getColor() {
		return this.color;
	}
}
public class EnumExample2 {
	public static void main(String[] args) {
		for (MyColor myColor : MyColor.values()) {
			System.out.println(myColor);
			System.out.println(myColor.getSummy());
			System.out.println(myColor.getColor());
			System.out.println("===================");
		}
		MyColor color1 = MyColor.valueOf("RED");
		System.out.println(color1);
		System.out.println(color1.getSummy());
		System.out.println(color1.getColor());
	}
}

 

3.3 枚举类实现接口

 

枚举类也可以实现一个接口,但是因为接口会存在抽象方法,所以枚举类中的每个实例对象都必须实现此抽象方法。如下所示:

public interface Print {
	public String getColor();
}
public enum MyColor implements Print {
	RED{
		@Override
		public String getColor() {
			return "红色";
		}
	},
	GREEN{
		@Override
		public String getColor() {
			return "绿色";
		}
	},
	BLUE{
		@Override
		public String getColor() {
			return "蓝色";
		}
	};
}
public class InterfaceEnumDemo {
	public static void main(String[] args) {
		for (MyColor c : MyColor.values()) {
			System.out.println(c.getColor());
		}
	}
}

 

3.4 枚举类中定义抽象方法

 

枚举类除了可以实现接口外,还可以咋枚举类中定义抽象方法,这样每个枚举的对象只要分别实现了此抽象方法即可。

public enum MyColor {
	RED{
		public String getColor() {
			return "红色";
		}
	},
	GREEN{
		public String getColor() {
			return "绿色";
		}
	},
	BLUE{
		public String getColor() {
			return "蓝色";
		}
	};
	//抽象方法
	public abstract String getColor() ;
}
for (MyColor2 c : MyColor2.values()) {
		System.out.println(c.getColor());
}

 

 

4. Enum

在上面已经清楚地知道,使用enum关键字可以定义一个枚举,实际上此关键字表示的是java.lang.Enum类型,即使有enum声明的枚举类型就相当于定义了一个类。而此类则默认继承java.lang.Enum类。java.lang.Enum类的定义如下:

public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable

Enum类的定义中可以清楚地发现,此类实现了ComparableSerializable接口,说明枚举类可以使用比较器和序列化操作。

 

4.1 获取枚举的信息

 

在枚举定义完成之后,实际上都会为其调用枚举类中的构造方法,为其赋值。在Enum类的构造方法中的第一个参数name,就是定义的枚举名称,第二个参数ordinl则会从0开始依次进行编号。之后可以使用Enum类中提供的name()ordinal()方法取得名称和编号。

public enum MyColor {
	RED, BLUE, GREEN
}
public class EnumExample {

	public static void main(String[] args) {
		for (MyColor myColor : MyColor.values()) {
			System.out.println(myColor.ordinal() +"-->"+ myColor.name());
		}
	}
}

 

4.2 为枚举对象属性赋值

4.2.1通过构造方法为属性赋值

 

每个枚举类中都有其指定好的若干对象,当然,每个枚举对象中也可以包含多个属性。

public enum Coin {
	penny("one"),
	nickel("five"),
	dime("yijiao"),
	quarter("quarter");
	
	private String value;
	
	private Coin(String value) {//唯一的构造方法
		this.value = value;
	}
	
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public static void main(String[] args) {
		Coin coin = Coin.dime;
		System.out.println(coin.getValue());
		System.out.println("-----------------");
		for (Coin c : Coin.values()) {
			System.out.println(c.ordinal()+"-->"+c.name());
		}
	}
}

以上程序定义的Coin枚举类型中设置了一个name属性,并且通过构造方法设置name属性的内容。

penny("one"),nickel("five"),dime("yijiao"),	quarter("quarter");

 

4.2.2通过setter方法为属性赋值

 

通过调用setter()方法为指定的属性赋值,但是这样一来就必须明确每一个枚举类的对象。

public enum Color {
	RED,GREEN,BLUE;
	private String name ;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		switch (this) {
		case RED:
			if ("红色".equals(name)) {
				this.name = name;
			}else {
				System.out.println("error!");
			}
			break;
		case GREEN:
			if ("绿色".equals(name)) {
				this.name = name;
			}else {
				System.out.println("error!");
			}
			break;
		case BLUE:
			if ("蓝色".equals(name)) {
				this.name = name;
			}else {
				System.out.println("error!");
			}
			break;
		}
	}
	
	public static void main(String[] args) {
		Color color = Color.BLUE;
		color.setName("蓝色");
		color.setName("兰色");
		System.out.println(color.getName());
	}
}

如果不想通过“枚举类.对象”的形式取得每一个枚举类的对象,也可以使用Enum类定义的“枚举类.valueof()”方法的形式进行调用。

Color color = Enum.valueOf(Color.class, "BLUE");

 

4.3 使用比较器

 

Enum类的定义中已经实现了Comparable接口,所以枚举类的内容本身是可以进行排序的,下面通过TreeSet演示枚举排序操作。

Set<Color> t = new TreeSet<Color>();
t.add(Color.GREEN);
t.add(Color.BLUE);
t.add(Color.RED);
Iterator<Color> iter = t.iterator();
while (iter.hasNext()) {
	System.out.print(iter.next()+" ");
}

 

4.4 遍历枚举接口的元素

 

集合类可以用来管理一组相关的对象。当需要查看、使用集合中的所有对象时可以使用枚举接口对其进行遍历。枚举接口(Enumeration)中定义了两个方法,hasMoreElements和nextElement,它通常和向量一起使用。

/**
 * @desc 枚举接口Enumeration测试 
 */
public class EnumerationTest {

	public static void main(String[] args) {
		Vector<Color> v = new Vector<Color>();
		v.add(Color.RED);
		v.add(Color.BLUE);
		
		Enumeration<Color> e = v.elements();
		while (e.hasMoreElements()) {
			Color color =  e.nextElement();
			System.out.println(color);
		}
	}
}

 

5. 枚举集合

 

JDK5.0java.util程序包中提供了两个新的集合操作类:EnumMapEnumSet。这两个类与枚举类型的结合应用可以使非常繁琐的程序变得简单方便。

 

5.1 EnumSet

 

EnumSet用于保存枚举项的集合,在枚举项本身并不互斥的情况下特别有用。例如,一个应用系统通常会有多种角色,而某些人在系统中可能承担不止一种角色。如果这些角色是通过枚举定义的,则此时EnumSet将可以将多种角色保存在一起,标识特定用户承担的全部角色。

EnumSet扩展于AbstractSet,它除了拥了普通Set所拥有的方法外,主要是增加了一系列可产生EnumSet实例的方法(noneOfallOfcopyOfcomplementOfofrange),使用EnumSet时不能直接使用new为其进行实例化。

以下是使用EnumSetof方法产生一个EnumSet实例的示例。

public enum Color {
	RED,GREEN,BLUE;
}
//EnumSet<Color> es = EnumSet.of(Color.BLUE,Color.GREEN);
EnumSet<Color> es = EnumSet.allOf(Color.class);
for (Color color : es) {
	System.out.println(color);
}

 

5.2 EnumMap

 

EnumMap是必须使用枚举项作为其KEYMap,其法与普通Map类似。以下例程将两类角色的中文含义置入到一个EnumMap对象中,并随后调用了EnumMapsizeget方法。

enum Role{
    SYSADMIN,
    ROLEA,
    ROLEB,
    ROLEC;
}
public class EnumMapExample{
    public static void main(String[] args){
        EnumMap<Role, String> em = newEnumMap<Role, String>(Role.class);
        em.put(Role.SYSADMIN, "系统管理员");
        em.put(Role.ROLEA, "角色A");        
        System.out.println(em.size());
        System.out.println(em.get(Role.SYSADMIN));
    }
}

 

 

 

 

 

 

------- android培训java培训、期待与您交流! ----------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值