文章目录

  • 1. 概念
  • 1. 什么时候用枚举
  • 2. 语法
  • 3. 枚举集合
  • 4. 枚举 API
  • 5. 枚举的本质


1. 概念

1. 什么时候用枚举

程序中某个变量取值仅限于集合中的元素。此时,可将这些数据集合定义为枚举类型。

2. 语法

枚举类与类、接口是同等地位的,他可以实现多个接口,可以有构造器 ,方法 ,属性等等。

枚举类和普通类的区别在于,枚举类默认继承 java.lang.Enum 类,其中 java.lang.Enum 类实现了 java.lang.Serializable 和 java.lang.Comparable 接口;所有枚举类默认被 final 修饰,即枚举类不可被继承;所有构造器默认被 private 修饰,也只能被 private 修饰;枚举类的所有实例必须位于第一行,默认被 public static final 修饰。

枚举实例可以有 n 个参数,如果 n 不为 0,则要求枚举类中必须存在一个包含 n 个参数的构造器,如:

enum Color implements Print{
    //每个颜色都是枚举类的一个实例,并且构造方法要和枚举类的格式相符合。
    //如果实例后面有其他内容,实例序列结束时要加分号。
    Red("红色", 1), Green("绿色", 2), Blue("蓝色", 3), Yellow("黄色", 4), Glay;
    
    String name;
    int index;
    
    Color() {}
    
    Color(String name, int index) {
        this.name = name;
        this.index = index;
    }
    
    //重写接口中的方法
    @Override
    public void print() {
        System.out.println(this.name);
    }
    
    //因为默认继承了 Enum 父类,所以可以重写父类中的方法
	@Override
	public String toString() {
	    return this.index + ":" + this.name;
	}
    
    public void showAllColors() {
        //values是Color实例的数组,在通过index和name可以获取对应的值。
        for (Color color : Color.values()) {
            System.out.println(color.index + ":" + color.name);
        }
    }
}

枚举类型对象之间的值比较:使用 == 直接来比较值,枚举类 Enum 已经重写了 equals 方法

//Enum 源码
public final boolean equals(Object other) {
    return this==other;
}

3. 枚举集合

EnumSet 存储 Enum 类型的集合,且集合元素不重复,因为 EnumSet 是一个抽象类,所以要用它的话,需要子类去继承它;EnumMap 存储 key 为 Enum 类型,value 为任意类型的键值对

public class 枚举类集合 {
    public static void main(String[] args) {
        EnumMap<Color, String> map = new EnumMap<Color, String>(Color.class);
        map.put(Color.Blue, "Blue");
        map.put(Color.Yellow, "Yellow");
        map.put(Color.Red, "Red");
        System.out.println(map.get(Color.Red));
    }
}

如果枚举类数量比较多,可以使用接口来组织枚举类

class TestEnumByInterface {
    public static void main(String[] args) {
        Food cf = chineseFood.dumpling;  // 没有定义在接口里面
        Food food = Food.JapaneseFood.fishpiece; //定义在接口里面,接口中的枚举需要用 接口名.枚举名 来调用
        food = Food.Coffee.BLACK_COFFEE;
        for (Food food1 : chineseFood.values()) {
            System.out.println(food1);
        }
        for (Food food1 : Food.JapaneseFood.values()) {
            System.out.println(food1);
        }
    }
}

interface Food { // 接口里面定义多个枚举类
    enum JapaneseFood implements Food {
        suse, fishpiece;
    }

    enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, ESPRESSO, LATTE, CAPPUCCINO, TEA, HERB_TEA;
    }
}

enum chineseFood implements Food { //这个枚举类没有定义在接口里面
    dumpling, tofu;
}

//结果
dumpling
tofu
suse
fishpiece

4. 枚举 API

  • String name():获取枚举实例名称
  • int ordinal():获取枚举的位置(下标,默认初始值为 0,如果是自定义的话,就返回自定义的整数值 )
  • valueof(String msg):通过枚举实例名称获取其对应的枚举类型
  • values():获取枚举类中的所有枚举值(枚举实例),返回一个包含所有枚举实例的数组,枚举类名.values()

5. 枚举的本质

枚举本质上是通过普通的类来实现的,只是编译器为我们进行了处理。每个枚举类型都继承自 java.lang.Enum,并自动添加了 values 和 valueOf 方法;每个枚举常量(即枚举实例)是一个静态常量字段,使用内部类实现,该内部类继承了枚举类。

第一,所有枚举常量都通过静态代码块来进行初始化,即在类加载期间就初始化;第二,通过把 clone 定义为 final 修饰、readObject 定义为 private 来保证了每个枚举类型及枚举常量都是不可变的。可以利用枚举的这两个特性来实现线程安全的单例