【Java基础篇】枚举 (enum)
Java 枚举(enum)
Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。枚举类和正常类一样,也可以有成员变量、实例方法、静态方法、抽象方法
。
例如定义一个颜色的枚举类。
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
// 执行输出结果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1); //RED
}
}
以上枚举类 Color
颜色常量有 RED, GREEN, BLUE
,分别表示红色,绿色,蓝色。
每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的。
以上的枚举类 Color 转化在内部类实现:
class Color
{
public static final Color RED = new Color();
public static final Color BLUE = new Color();
public static final Color GREEN = new Color();
}
values(), ordinal() 和 valueOf() 方法
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Seriablizable 和 java.lang.Comparable 两个接口。
values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:
- values() 返回枚举类中所有的值。
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
- valueOf()方法返回指定字符串值的枚举常量。
1. 枚举类常量
//首先枚举是一个特殊的class
//这个class相当于final static修饰,不能被继承
//他的构造方法强制被私有化,下面有一个默认的构造方法private ColorEnum();
//所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类
public enum ColorEnum {
//每个枚举变量都是枚举类ColorEnum的实例,相当于RED=new ColorEnum(1),按序号来。
//每个成员变量都是final static修饰
RED, GREEN, BLANK, YELLOW;
}
测试类:
@Test
public void ColorTest() {
//ordinal返回枚举变量的序号
//values() 返回枚举类中所有的值。
for(ColorEnum color:ColorEnum.values()) {
System.out.println(color+",ordinal:"+color.ordinal()+",name:"+color.name());
}
}
2. 带一个参数的枚举
public enum TypeEnum {
FIREWALL("firewall"),
SECRET("secretMac"),
BALANCE("f5");
private String typeName;
TypeEnum(String typeName) {
this.typeName = typeName;
}
/**
* 根据类型的名称,返回类型的枚举实例。
* @param typeName 类型名称
*/
public static TypeEnum fromTypeName(String typeName) {
for (TypeEnum type : TypeEnum.values()) {
if (type.getTypeName().equals(typeName)) {
return type;
}
}
return null;
}
/**
* Stream流写法
* @param typeName 类型名称
*/
public static TypeEnum getByName(String typeName) {
return Arrays.stream(values()).filter(o -> o.getTypeName().equals(typeName)).findFirst().orElse(null);
}
public String getTypeName() {
return this.typeName;
}
}
测试类:
@Test
public void TypeTest() {
String typeName = "f5";
TypeEnum type = TypeEnum.fromTypeName(typeName);
//type:是TypeEnum类实例化对象 typeName:实例化对象type的值
//ordinal:实例化对象type的序号(int) 排序值(默认自带的属性 ordinal 的值)
//name:实化对象的名字(String) 枚举名称(即默认自带的属性 name 的值)
System.out.println(type+",typeName:"+type.getTypeName()+",ordinal:"+type.ordinal()+",name:"+type.name());
}
3. 向枚举类中添加新方法
public enum SeasonEunm {
//每一个枚举变量都是枚举类SeasonEunm的实例化
//SeasonEunm.SPRING获得的对象相当于new SeasonEunm("春","春困");获得的对象
SPRING("春","春困"),SUMMER("夏","夏睡"),AUTUMN("秋","秋乏"),WINTER("冬","冬眠");
//强制私有化的构造方法,因为枚举类默认继承Eunm类,被final static修饰,不能被继承
//由于被强制private,所以不能使用new去生成枚举对象
//在SeasonEunm.SPRING获得对象,隐式调用了下面的构造方法
// 构造方法 ,赋值给成员变量
private SeasonEunm(String name, String value) {
this.name = name;
this.value = value;
}
//添加成员变量的原因是,方便够着方法赋值,使用SeasonEunm.SPRING.getName就能获取对应的值
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
测试类:
@Test
public void SessionTest() {
//ordinal返回枚举变量的序号 迭代枚举元素
for(SeasonEunm seasion:SeasonEunm.values()) {
System.out.println(seasion+",ordinal:"+seasion.ordinal()+",name:"+seasion.name());
System.out.println("枚举变量值:"+seasion.getName()+",枚举变量值:"+seasion.getValue());
}
}
4. 覆盖枚举的方法
public enum RGBEnum {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法 ,赋值给成员变量
private RGBEnum(String name, int index) {
this.name = name;
this.index = index;
}
//覆盖方法 :只能使用toString方法来输出枚举变量值
@Override
public String toString() {
return this.index+"_"+this.name;
}
}
测试类:
@Test
public void RGBEnumTest() {
// values() 返回枚举类中所有的值。
for(RGBEnum rgb:RGBEnum.values()) {
System.out.println(rgb.toString());
}
}
5. 在 switch 中使用枚举类
枚举类常应用于 switch 语句中:
enum Color
{
RED, GREEN, BLUE;
}
public class MyClass {
public static void main(String[] args) {
Color myVar = Color.BLUE;
switch(myVar) {
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
}
}
6.实现接口,消除 if/else
我们创建的枚举类默认是被final修饰,并且默认继承了Enum类。因此不能再继承其他的类。但是可以去实现接口。
有这样一个判断场景。
if ("dog".equals(animalType)){
System.out.println("吃骨头");
} else if ("cat".equals(animalType)) {
System.out.println("吃鱼干");
} else if ("sheep") {
System.out.println("吃草");
}
怎样用枚举来消除掉 if/else 呐,看下面的代码:
先定义一个接口,里面有一个通用方法 eat()
public interface Eat {
//吃
String eat();
}
然后创建枚举类实现这个接口
public enum AnimalEnum implements Eat {
Dog(){
@Override
public void eat() {
System.out.println("吃骨头");
}
},
Cat() {
@Override
public void eat() {
System.out.println("吃鱼干");
}
},
Sheep() {
@Override
public void eat() {
System.out.println("吃草");
}
}
}
调用的时候只需要一行代码:
public class Test {
public static void main(String[] args) {
AnimalEnum.valueOf("Cat").eat(); // 吃鱼干
}
}
而且这样一来,以后假如我想扩充新的动物,只需要去枚举类中加代码即可,而不用改任何老代码,符合开闭原则!
7.枚举类中定义抽象方法
枚举类除了可以实现接口外,还可以在枚举类中定义抽象方法,这样每个枚举的对象只要分别实现了此抽象方法即可。
enum Color{
RED{
public String getColor(){//枚举对象实现抽象方法
return "红色";
}
},
GREEN{
public String getColor(){//枚举对象实现抽象方法
return "绿色";
}
},
BLUE{
public String getColor(){//枚举对象实现抽象方法
return "蓝色";
}
};
public abstract String getColor();//定义抽象方法
}
public class Test{
public static void main(String[] args) {
for (Color c:Color.values()){
System.out.print(c.getColor() + "、");
}
}
}
8. 单例模式中应用
枚举在单例模式的一种实现方式中也可以用到。
/**
* @Description: 枚举 线程安全
*/
public class SingletonExample {
/**
* 构造函数私有化,避免外部创建实例
*/
private SingletonExample(){}
private static SingletonExample getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private SingletonExample instance;
// JVM 保证这个方法绝对只调用一次
Singleton() {
instance = new SingletonExample();
}
public SingletonExample getInstance() {
return instance;
}
}
}