定义
enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性,存放在 java.lang 包中。
它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。
关键词enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件来使用 。
《Java编程思想第四版》
源码
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable{}
在什么情况使用枚举?
当需要一个类的对象有限且固定,需要使用public static final 修饰的时候,可以使用枚举...
枚举类更加直观,类型安全。使用常量会有以下几个缺陷:
1. 类型不安全。若一个方法中要求传入季节这个参数,用常量的话,形参就是int类型,开发者传入任意类型的int类型值就行,但是如果是枚举类型的话,就只能传入枚举类中包含的对象。
2. 没有命名空间。开发者要在命名的时候以SEASON_开头,这样另外一个开发者再看这段代码的时候,才知道这四个常量分别代表季节。
枚举
package enumcase;
public enum SeasonEnum {
SPRING,SUMMER,FALL,WINTER;
}
1、enum 、class 、interface相同的存在
2、使用enum定义的枚举类默认继承了java.lang.Enum,而不是继承Object类。枚举类可以实现一个或多个接口。
3、枚举类的所有实例都必须放在第一行展示,不需使用new 关键字,不需显式调用构造器。自动添加public static final修饰。
4、使用enum定义、非抽象的枚举类默认使用final修饰,不可以被继承。
5、枚举类的构造器只能是私有的。
使用反编译工具编译后:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: SeasonEnum.java
package com.aozhi.enumTest;
//自定义的枚举基础了Enum
public final class SeasonEnum extends Enum
{
//私有构造方法,这里调用了父类的构造方法,其中参数s对应了常量名,参数i代表枚举的一个顺序(这个顺序与枚举的声明顺序对应,用于oridinal()方法返回顺序值
private SeasonEnum(String s, int i)
{
super(s, i);
}
//返回存储枚举实例的数组的副本。values()方法通常用于foreach循环遍历枚举常量。
public static SeasonEnum[] values()
{
SeasonEnum aseasonenum[];
int i;
SeasonEnum aseasonenum1[];
System.arraycopy(aseasonenum = ENUM$VALUES, 0, aseasonenum1 = new SeasonEnum[i = aseasonenum.length], 0, i);
return aseasonenum1;
}
//根据实例名获取实例
public static SeasonEnum valueOf(String s)
{
return (SeasonEnum)Enum.valueOf(com/aozhi/enumTest/SeasonEnum, s);
}
//我们定义的枚举在这里声明了三个 SeasonEnum的常量对象引用,对象的实例化在static静态块中
public static final SeasonEnum SPRING;
public static final SeasonEnum SUMMER;
public static final SeasonEnum FALL;
public static final SeasonEnum WINTER;
private static final SeasonEnum ENUM$VALUES[];
static
{
SPRING = new SeasonEnum("SPRING", 0);
SUMMER = new SeasonEnum("SUMMER", 1);
FALL = new SeasonEnum("FALL", 2);
WINTER = new SeasonEnum("WINTER", 3);
//将所有枚举的实例存放在数组中
ENUM$VALUES = (new SeasonEnum[] {
SPRING, SUMMER, FALL, WINTER
});
}
}
枚举类内也可以定义属性和方法,可是是静态的和非静态的。
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例
package com.aozhi.enumTest;
public enum SeasonEnum {
// SPRING,SUMMER,FALL,WINTER;
//枚举类的所有实例都必须放在第一行展示
SPRING("春天"),SUMMER("夏天"),FALL("秋天"),WINTER("冬天");
private final String name;
//当重载有参构造,就无法使用默认的无参构造
private SeasonEnum(String name)
{
System.out.println("季节枚举构造");
this.name = name;
}
public String getName() {
return name;
}
}
执行结果:
说明:1、枚举中的所有实例必须放在枚举中的第一行的位置
2、每个实例调用构造方法,进行初始化
3、构造器需定义成私有的,这样就不能在别处申明此类的对象了。枚举类通常应该设计成不可变类,它的Field不应该被改变,这样会更安全,而且代码更加简洁。所以我们将Field用private final修饰。
枚举实现接口:
枚举类可以实现一个或多个接口。与普通类一样,实现接口的时候需要实现接口中定义的所有方法,若没有完全实现,那这个枚举类就是抽象的,只是不需显式加上abstract修饰,系统化会默认加上。
package com.aozhi.enumTest;
public enum Operation {
PLUS{
@Override
public double eval(double x, double y) {
return x + y;
}
},
MINUS{
@Override
public double eval(double x, double y) {
return x - y;
}
},
TIMES{
@Override
public double eval(double x, double y) {
return x * y;
}
},
DIVIDE{
@Override
public double eval(double x, double y) {
return x / y;
}
};
/**
* 抽象方法,由不同的枚举值提供不同的实现。
* @param x
* @param y
* @return
*/
public abstract double eval(double x, double y);
public static void main(String[] args) {
System.out.println(Operation.PLUS.eval(10, 2));
System.out.println(Operation.MINUS.eval(10, 2));
System.out.println(Operation.TIMES.eval(10, 2));
System.out.println(Operation.DIVIDE.eval(10, 2));
}
}
Operatio类实际上是抽象的,不可以创建枚举值,所以此处在申明枚举值的时候,都实现了抽象方法,这其实是匿名内部类的实现,花括号部分是一个类体。我们可以看下编译以后的文件。
共生成了五个class文件,这样就证明了PLUS,MINUS,TIMES,DIVIDE是Operation的匿名内部类的实例。
来源:https://www.cnblogs.com/sister/p/4700702.html
由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的,如下:
package com.zejian.enumdemo;
/**
* Created by zejian on 2017/5/8.
* Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
*/
interface food{
void eat();
}
interface sport{
void run();
}
public enum EnumDemo2 implements food ,sport{
FOOD,
SPORT,
; //分号分隔
@Override
public void eat() {
System.out.println("eat.....");
}
@Override
public void run() {
System.out.println("run.....");
}
}
有时候,我们可能需要对一组数据进行分类,比如进行食物菜单分类而且希望这些菜单都属于food类型,appetizer(开胃菜)、mainCourse(主菜)、dessert(点心)、Coffee等,每种分类下有多种具体的菜式或食品,此时可以利用接口来组织,如下(代码引用自Thinking in Java):
public interface Food {
enum Appetizer implements Food {
SALAD, SOUP, SPRING_ROLLS;
}
enum MainCourse implements Food {
LASAGNE, BURRITO, PAD_THAI,
LENTILS, HUMMOUS, VINDALOO;
}
enum Dessert implements Food {
TIRAMISU, GELATO, BLACK_FOREST_CAKE,
FRUIT, CREME_CARAMEL;
}
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
LATTE, CAPPUCCINO, TEA, HERB_TEA;
}
}
public class TypeOfFood {
public static void main(String[] args) {
Food food = Appetizer.SALAD;
food = MainCourse.LASAGNE;
food = Dessert.GELATO;
food = Coffee.CAPPUCCINO;
}
}
---------------------
通过这种方式可以很方便组织上述的情景,同时确保每种具体类型的食物也属于Food,现在我们利用一个枚举嵌套枚举的方式,把前面定义的菜谱存放到一个Meal菜单中,通过这种方式就可以统一管理菜单的数据了。
public enum Meal{
APPETIZER(Food.Appetizer.class),
MAINCOURSE(Food.MainCourse.class),
DESSERT(Food.Dessert.class),
COFFEE(Food.Coffee.class);
private Food[] values;
private Meal(Class<? extends Food> kind) {
//通过class对象获取枚举实例
values = kind.getEnumConstants();
}
public interface Food {
enum Appetizer implements Food {
SALAD, SOUP, SPRING_ROLLS;
}
enum MainCourse implements Food {
LASAGNE, BURRITO, PAD_THAI,
LENTILS, HUMMOUS, VINDALOO;
}
enum Dessert implements Food {
TIRAMISU, GELATO, BLACK_FOREST_CAKE,
FRUIT, CREME_CARAMEL;
}
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
LATTE, CAPPUCCINO, TEA, HERB_TEA;
}
}
}
博客地址:https://blog.csdn.net/javazejian/article/details/71333103
switch语句里的表达式可以是枚举值
case表达式中直接写入枚举值,不需加入枚举类作为限定。
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
---------------------------------------------------------------小生是一条霸气的分割线------------------------------------------------------------------
package com.angus.testenum;
/**
* <p>Title: TestEnum</p>
* <p>Description: </p>
* @author angus
* @date 2018年10月17日
*/
public class TestEnum {
/**
*
* <p>Title: Season</p>
* <p>Description:简单的枚举类 </p>
* @author angus
* @date 2018年10月17日
*/
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
/**
*
* <p>Title: Color</p>
* <p>Description:使用构造方法,给枚举赋值 </p>
* @author angus
* @date 2018年10月17日
*/
enum Color{
RED("红色"),YELLOW("黄色"),BLUE("蓝色");
private String name;
private Color(String name) {
this.name=name;
}
public String getName() {
return this.name;
}
public static Color fromColorName(String colorName) {
for (Color color : Color.values()) {
if(colorName.equals(color.getName())) {
//System.out.println("");
return color;
}
}
return null;
}
}
private static void forEnum() {
for (Season season : Season.values()) {
System.out.println("season::"+season+",ordinal::"+season.ordinal());
}
System.out.println("==================小生是条霸气的分割线============================");
for (Color color : Color.values()) {
System.out.println("color::"+color+",colorName::"+color.name+",ordinal::"+color.ordinal());
}
}
private static void useEnumInJava() {
String colorName="黄色";
Color color= Color.fromColorName(colorName);
if(color==(Color.YELLOW)) {
System.out.println("This is same");
}else {
System.out.println("angus error");
}
}
public static void main(String[] args) {
forEnum();
System.out.println("++++++++++++++++++小生是条霸气的分割线的弟弟++++++++++++++");
useEnumInJava();
}
}
结果::
枚举的实例末尾以分号“;”结尾
枚举的构造方法必须是私有的,不可像类一样在任何地方进行实例化new ,枚举的实例只能是在枚举内,枚举的实例是有限的,这种限制了范围的,在一些情况下的时候更为方便,简单
___________________________________小生是条不那么讲究的分割线——————————————————————
枚举使用的规范:规范而已,开心就好