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;
}
}
这种方式也是线程安全的、延迟初始化的,单一的。