Java 5里新引用了枚举类型,这篇文章简单介绍一下它的基本用法。

 

一、Name

最简单的枚举定义如下:

enum Colors {
	RED, GREEN, BLACK
}

例如以下定义打印其中某个值的名称:

Colors c = Colors.RED;
		System.out.println(c.name());
		System.out.println(c);

打印结果为:

RED
RED

可以看到它的toString()方法就是返回它的name,可以看 java.lang.Enum<E> 的源码:

public String toString() {
        return name;
    }

可以重写toString()方法来返回不同于name的值,例如:

enum Colors {
	RED, GREEN, BLACK;

	@Override
	public String toString() {
		return "Color: "+name();
	}
	
}

再运行上面的程序,返回就是:

RED
Color: RED

二、序号

默认情况下,Enum中定义的每个值都有一个从0开始的序号,例如以上Color的序号分别是:

RED=0
GREEN=1
BLACK=2

可以能序号去获得它对应的值,例如:

System.out.println(Colors.values()[2]);

打印的结果就是BLACK.

三、用于Switch

Enum对象可以用于Switch语句,例如:

Colors c = ...;
		switch (c) {
		case BLACK:
			System.out.println("black");
			break;
		case GREEN:
			System.out.println("green");
			break;
		case RED:
			System.out.println("red");
			break;

		default:
			break;
		}

四、增加方法和变量

Enum里也可以增加方法和变量,例如:

enum Colors {
	
	RED(3), GREEN(6), BLACK(9);
	
	int index;
	Colors(int index){
		this.index = index;
	}
	
	public int getIndex() {
		return index;
	}
}

注意1:Java要求枚举类型中的所有枚举常量需要定义在所有的变量、构造函数和方法之前;并且如果有变量和方法存在,则常量列表最后要以分号(;)结束。

注意2:枚举中的构造函数只能是private,也即不能通过new来创建新的对象。

 

五、valueOf()方法

valueOf()方法可以把将字符串转成对应的Enum里的值,例如:

Colors valueOf = Colors.valueOf("RED");
		System.out.println(Colors.RED==valueOf);

六、重写方法

每一个Enum的值也可以重写Enum类定义中的方法,例如上面我们增加了一个index对象,然后用getIndex()方法返回这个值。我们也可以不传入index,通过重写getIndex()方法来实现:

enum Colors {

	RED{
		@Override
		public int getIndex() {
			return 3;
		}
	},
	GREEN{
		@Override
		public int getIndex() {
			return 6;
		}
	},
	BLACK{
		@Override
		public int getIndex() {
			return 9;
		}
	};

	public abstract int getIndex();
}

七、values()方法

values()方法可以返回所有定义的枚举值,例如:

Colors[] values = Colors.values();
		for(Colors c: values){
			System.out.println(c);
		}

八、实现接口

枚举类型也可以实现接口,例如:

interface Indexable{
	public int getIndex();
}

enum Colors implements Indexable {

	RED{
		public int getIndex() {
			return 3;
		}
	},
	GREEN{
		public int getIndex() {
			return 6;
		}
	},
	BLACK{
		public int getIndex() {
			return 9;
		}
	};
}

注意:枚举类型可以实现接口,但是不能继承类,因为所以有枚举类型都隐含的继承了类java.lang.Enum,而Java只允许单继承。

 

九、EnumSet和EnumMap

EnumSet是Java提供的一个特别的用来存储枚举值的Set,例如:

EnumSet<Colors> allColors = EnumSet.allOf(Colors.class);
		for(Colors c: allColors){
			System.out.println(c);
		}
		EnumSet<Colors> noneOf = EnumSet.noneOf(Colors.class);
		for(Colors c: noneOf){
			System.out.println(c);
		}
		noneOf.add(Colors.BLACK);
		noneOf.add(Colors.BLACK);
		System.out.println(noneOf);

EnumMap类似于EnumSet,不过这次是map形式的,键值为一个Enum值,值可以是任意的,例如:

EnumMap<Colors, String> map = new EnumMap<Colors, String>(Colors.class);
		map.put(Colors.RED, "red");
		map.put(Colors.BLACK, "black");
		map.put(Colors.GREEN, "green");
		map.put(Colors.RED, "red2");
		System.out.println(map);

  

十、实现单例

另一个Enum的很好的用处就是实现单例,以前实现单例的方式有:

双重锁定:

public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;
  
     private DoubleCheckedLockingSingleton(){}
  
     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

Read more: http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html#ixzz2ws3osFML

或者直接初始化静态变量:

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();
  
    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

Read more: http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html#ixzz2ws3v4BTa

但是他们都有各自的缺点:要么就是太复杂、要么就是不能延迟初始化、要不就是系列化时如果不做特定处理还是有问题。

 

而使用Enum就有很多好处:简单、安全:

public enum EasySingleton{
    INSTANCE;
}

 

补充:

另外一种单例的实现方式:

public class TestSingleton {

	private static class SingletonHelper{
		static TestSingleton INSTANCE = new TestSingleton();
	}
	
	private TestSingleton(){
		
	}
	
	public static TestSingleton getInstance(){
		return SingletonHelper.INSTANCE;
	}
}

这种方式也是线程安全的、延迟初始化的,单一的。