Ⅰ. 定义与使用
public enum Color {
*RED*, *GREEN*, *BLUE*, *YELLOW*, *ORANGE*, *PURPLE*, *PINK*, *BROWN*, *BLACK*, *WHITE*;
}每个我们写的 enum 类都会默认继承于一个抽象类 Enum,如下图所示:

而这个 Enum 抽象类中有挺多方法,如下所示:

下面是使用举例:
public static void main(String[] args) {
// 使用Color.RED直接访问枚举元素,或者直接RED都行,但不能使用new来生成枚举类对象
Color color = Color.*RED*;
System.*out*.println(color.name()); *// 输出颜色名称*
* *System.*out*.println(color.ordinal()); *// 输出颜色的序号*
* *System.*out*.println(color); *// 直接输出颜色对象*
* *System.*out*.println(color.describeConstable()); *// 输出颜色的描述信息*
* *System.*out*.println(Color.*valueOf*("BLACK")); *// 通过名称获取枚举值*
* // 有个比较特殊的是values()方法,它可以返回所有枚举值数组,它不存在Enum中,而是在编译时由编译器生成的。*
* // 但是如果枚举值太多,可能导致内存溢出,所以一般不用这个方法。*
* *System.*out*.println("----------------------输出所有枚举元素:");
Color[] colors = Color.*values*();
for(int i = 0; i < colors.length; ++i) {
System.*out*.println(colors[i] + " " + colors[i].ordinal());
}
Color c2 = new Color(); *// ❌不能实例化枚举类,只能通过枚举值访问其属性和方法。 *
}
// 运行结果:
RED
0
RED
Optional[EnumDesc[Color.RED]]
BLACK
----------------------输出所有枚举元素:
RED 0
GREEN 1
BLUE 2
YELLOW 3
ORANGE 4
PURPLE 5
PINK 6
BROWN 7
BLACK 8
WHITE 9这里要注意 values()是由 Java编译器为每个枚举类自动生成的静态方法 ,所以在 Enum 类里是找不到它的源码的,但每个具体的枚举类都有它。
还有就是枚举类内也可以有方法 ,并且这些方法只能通过枚举元素来调用 ,而不能直接通过枚举类名来调用,如下图所示:

Ⅱ. 枚举类的构造方法默认就是 private
枚举类的构造方法是隐式 private 的,是为了:
-
保证枚举常量的唯一性
-
避免外部创建新的实例(防止破坏
enum的封闭性) -
在某些场景下,天然实现单例模式,并且是线程安全的、防反射、防反序列化

首先枚举类也是可以写构造函数,然后枚举元素可以进行构造,如下所示:
public enum Color {
*RED*("red", 1), *GREEN*("green", 2), *BLUE*("blue", 3);
private String name;
private int value;
*// 构造函数默认就是private,不写也可以,但是不能写其它的访问权限*
* *private Color(String name, int value) {
this.name = name;
this.value = value;
}
public static void main(String[] args) {
Color c = Color.*RED*;
System.*out*.println(c.name);
System.*out*.println(c.value);
}
}
// 运行结果:
red
1然后测试一下不同对象引用同一个枚举元素,是不是同一地址:
public static void main(String[] args) {
Color c1 = Color.*RED*;
Color c2 = Color.*RED*;
System.*out*.println(c1 == c2); *// true*
}很明显不同对象引用同一个枚举元素,都是同一个对象 。
然后看一下是不是能够在类内调用构造方法:
public static void main(String[] args) {
Color c = new Color(); *// ❌报错:无法实例化枚举类型*
}那么就想,能不能用反射来设置访问权限,强制调用构造方法,如下所示:
public static void main(String[] args) {
try {
*// 先获取构造函数,再设置Accessible为true*
* *Class<?> cs = Class.*forName*("EnumDemo.Color");
Constructor<?> ctor = cs.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true);
*// 调用构造函数创建对象*
* *Color c = (Color)ctor.newInstance("yellow", 4);
System.*out*.println(c.name + " " + c.value);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}然后报了如下错误:

其实这个参数错误,是因为每个枚举类都默认继承了 Enum,而 Enum 类的构造方法又有两个参数,如下所示:

这时就需要一起放在我们的枚举类的参数列表中传入才行:
Constructor<?> ctor = cs.getDeclaredConstructor(String.class, int.class, String.class, int.class);解决上述问题之后,此时又有一个错误如下所示:

点击第二行跳转过去看看源码:

总结
-
Enum类同样有构造方法,但一定得是private修饰 。 -
Enum类的每一个枚举元素都是【单例】 。 -
Enum类型的类不能通过调用【构造方法】来创建实例 。 -
Enum类型的类不能通过【反射】来创建新的实例,因为Enum的实例在编译时就已经确定 ,且JVM保证了这些实例的唯一性。