每日一言 Hatred will never be erased! The only thing you can do is erase the ones you hate! – Hakuryū Ren from Magi - The Labyrinth of Magic
枚举(enum) Java枚举是一个特殊的类,一般表示一组常量,比如一年四个季节,一年的12个月份,一个星期的7天,方向的东西南北等。
枚举通过关键字 enum
来声明:
1 2 3 enum Season { SPRING,SUMMER,AUTUMN,WINTER; }
这样我们可以在代码中展示更加清晰的逻辑:
1 2 3 4 5 6 7 8 public class Main { public static void main (String[] args) { Season season = Season.SPRING; System.out.println("The current season is: " + season); } }
枚举类的实例化 对于我们上面的例子
1 Season season = Season.SPRING;
这句话只是创建了一个针对 Season.SPRING
的引用,也就是不论我们给多少个变量赋值为 Season.SPRING
在内存中都只有一个Season.SPRING的实例,其他都是指向它的引用。
这样的化我们可能会好奇一个问题:枚举类是在什么时候被实例化的呢?
我们写一个简单的程序来验证它:
1 2 3 4 5 6 7 8 9 10 11 12 13 enum Season { SPRING, SUMMER, AUTUMN, WINTER; Season() { System.out.println("Creating enum constant: " + this .name()); } }public class Main { public static void main (String[] args) { System.out.println("Main method started" ); } }
输出如下:
当我们没有引用任何的枚举常量时,枚举类并没有被实例化。接下来我们创建一个枚举类的引用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 enum Season { SPRING, SUMMER, AUTUMN, WINTER; Season() { System.out.println("Creating enum constant: " + this .name()); } }public class Main { public static void main (String[] args) { Season season = Season.SPRING; System.out.println("Main method started" ); } }
输出如下:
1 2 3 4 5 Creating enum constant: SPRING Creating enum constant: SUMMER Creating enum constant: AUTUMN Creating enum constant: WINTER Main method started
所以JVM会在首次引用枚举常量时,一次为所有的枚举常量进行实例化,顺序为我们申明的顺序。枚举类中的成员变量为每个创建的实例私有,方法为所有实例共有,与普通的类并无区别。
迭代枚举元素 可以使用for循环和 values()
方法来遍历枚举的每一个值。
1 2 3 4 5 6 7 public class Main { public static void main (String[] args) { for (Season s : Season.values()){ System.out.println(s); } } }
枚举类型的 values()
方法是Java枚举类型自动提供的一个静态方法。当你定义一个枚举类型时,Java编译器会自动为该枚举类型生成 values()
方法。
功能 这个方法会返回一个包含所有枚举常量的数组,数组中的元素按照它们在枚举声明中的顺序排序。
对于上面的例子来说,Season.values()
会返回一个枚举常量数组:
1 [Season.SPRING,Season.SUMMER,Season.AUTOMN,Season.WINTER]
在switch中使用枚举类 枚举类常应用于 switch 语句中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Main { public static void main (String[] args) { Season season = Season.SPRING; switch (season) { case SPRING: System.out.println("Spring is here!" ); break ; case SUMMER: System.out.println("Summer is here!" ); break ; case AUTUMN: System.out.println("Autumn is here!" ); break ; case WINTER: System.out.println("Winter is here!" ); break ; } } }
values(),ordinal(),valueOf()方法 enum 定义的枚举类默认继承了 java.lang.Enum()
类,这个类中包含了三种默认的方法:
values():返回枚举类中的值,返回为一个数组
ordinal():方法可以找到每个枚举常量的索引,就像数组的索引一样,顺序与声明顺序相同
valueOf():方法返回指定字符串值的枚举常量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Main { public static void main (String[] args) { Season[] seasons = Season.values(); for (Season season : seasons) { System.out.println(season); System.out.println("The ordinal of SPRING is: " + season.ordinal()); } Season tmp = Season.valueOf("SPRING" ); Season tmp1 = Season.SPRING; } }
输出:
1 2 3 4 5 6 7 8 SPRING The ordinal of SPRING is: 0 SUMMER The ordinal of SPRING is: 1 AUTUMN The ordinal of SPRING is: 2 WINTER The ordinal of SPRING is: 3
Season.valueOf("SPRING")
方法返回的枚举常量与直接使用 Season.SPRING
创建的枚举常量完全相同 ,它们的不同之处在于获取枚举常量的过程不同 。
Season.valueOf(SPRING)
这是一个 方法调用 ,通过字符串参数来获取对应的枚举常量
参数必须是字符串形式的枚举常量名称,且必须与枚举常量的名称完全匹配(包括大小写)
如果字符串参数不匹配任何枚举常量名称,会抛出 IllegalArgumentException
异常
适用于在运行时动态 获取枚举常量,例如从配置文件或用户输入中读取字符串后转换为枚举
Season.SPRING
这是直接引用 枚举常量
编译时就确定了引用的是哪个枚举常量
不会抛出异常(编译时检查)
代码更简洁,性能更好(不需要方法调用和异常处理)
适用于在编译时已知 需要使用哪个枚举常量的情况
枚举类成员 枚举跟普通类一样可以有自己的变量,方法和构造函数,但是构造函数 只能使用private 访问修饰符,所以外部无法调用。构造函数用于给枚举赋初值。
1 2 3 4 5 6 7 8 9 10 public enum Color { RED(255 ,0 ,0 ); private int r,g,b; private Color (int r, int g, int b) { this .r = r; this .g = g; this .b = b; } }
枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public enum Operation { ADD { @Override public double apply (double x, double y) { return x + y; } }, SUBTRACT { @Override public double apply (double x, double y) { return x - y; } }, MULTIPLY { @Override public double apply (double x, double y) { return x * y; } }, DIVIDE { @Override public double apply (double x, double y) { if (y == 0 ) { throw new ArithmeticException ("Division by zero" ); } return x / y; } }; public abstract double apply (double x, double y) ; }
枚举的实例都在类的里面申明。