Java 枚举类型
Java面向对象设计 - Java枚举类型
什么是枚举类型?
枚举类型创建常量的有序列表作为类型。它以特定顺序指定常量。
在枚举类型中定义的常量是该枚举类型的实例。
语法
使用关键字enum使用以下语法定义枚举类型:
<access-modifier> enum <enum-type-name> { // List of comma separated names of enum constants }
<access-modifiers>与类的访问修饰符相同:public,private,protected或package-level。
<enum-type-name>是有效的Java标识符。
枚举类型的主体放在大括号中,名称后面。主体可以有逗号分隔的常量和其他元素的列表,例如实例变量,方法等。
大多数时候,枚举体只包括常量。
例子
下面的代码声明了一个名为Gender的枚举类型,它声明了两个常量:MALE和FEMALE:
public enum Gender { MALE, FEMALE; // The semi-colon is optional }
将枚举常量命名为大写是一种惯例。
以下代码声明了一个名为Level的公共枚举类型,它具有四个枚举常量:LOW,MEDIUM,HIGH和URGENT。
public enum Level { LOW, MEDIUM, HIGH, URGENT; }
可以从应用程序中的任何位置访问公共枚举类型。
公共枚举类型保留在具有枚举类型名称的文件中。级别枚举将保存在名为Level.java的文件中。
我们需要在包中放置枚举类型,我们可以使用 import
语句导入枚举类型。
枚举变量
我们可以声明枚举类型的变量,就像声明类类型的变量一样。
以下代码声明Level枚举类型的errorLevel变量。
Level errorLevel;
您可以为枚举类型变量分配null,如下所示:
Level defectLevel = null;
在switch语句中使用枚举类型
您可以在switch语句中使用枚举类型。
当switch表达式是枚举类型时,所有case标签必须是同一枚举类型的不合格枚举常量。
enum Direction { East, South, West, North } public class Main { public static void main(String args[]) { Direction dir = Direction.South; switch (dir) { case South: System.out.println("south"); break; case East: System.out.println("East"); break; case West: System.out.println("West"); break; case North: System.out.println("North."); break; } } }
上面的代码生成以下结果。
嵌套枚举类型
我们可以在类,接口或另一个枚举类型中有一个嵌套的枚举类型声明。
嵌套枚举类型是隐式静态的。因为枚举类型总是静态的,所以我们不能在方法体内声明一个局部枚举类型。
对于嵌套枚举类型,我们可以使用任何访问修饰符(public,private,protected或package)级别。
以下代码显示了如何在Person类中声明名为Gender的嵌套公共枚举类型。
class Person { public enum Gender { MALE, FEMALE } } public class Main { public static void main(String[] args) { Person.Gender m = Person.Gender.MALE; Person.Gender f = Person.Gender.FEMALE; System.out.println(m); System.out.println(f); } }
Person.Gender枚举类型可以从应用程序中的任何位置访问,因为它已被声明为public。
我们也可以通过使用静态导入导入枚举常量来使用枚举常量的简单名称。
import static com.w3cschool.enums.Person.Gender.*;
实现枚举类型的接口
枚举类型可以实现接口。实现接口的枚举类型的规则与实现接口的类的规则相同。
下面的代码演示了如何让enum类型实现一个接口。
interface Command { void execute(); } enum Level implements Command { LOW { public void execute() { System.out.println("Low..."); } }, HIGH { public void execute() { System.out.println("HIGH..."); } }; public abstract void execute(); } public class Main { public static void main(String... args) { for (Command cmd : Level.values()) { cmd.execute(); } } }
上面的代码生成以下结果。
Java 枚举值
Java面向对象设计 - Java枚举值
枚举类型定义了两件事:
- 枚举常量
- 这些常量的顺序
以下代码声明了一个名为Level的公共枚举类型,它具有四个枚举常量:LOW,MEDIUM,HIGH和URGENT。
public enum Level { LOW, MEDIUM, HIGH, URGENT; }
Level枚举类型定义了四个枚举常量。
Level枚举类型的变量只能有四个值之一 - LOW,MEDIUM,HIGH和URGENT或null。
我们可以使用点符号通过使用枚举类型名称作为限定符来引用枚举常量。
以下代码将值分配给Level枚举类型的变量:
Level low = Level.LOW; Level medium = Level.MEDIUM; Level high = Level.HIGH; Level urgent = Level.URGENT;
我们不能实例化枚举类型。以下代码导致编译时错误:
Level badAttempt = new Level(); // A compile-time error
枚举分配顺序号
枚举类型为其所有常量分配一个顺序号,称为ordinal。
序数从零开始,在常数列表中从第一个到最后一个递增1。
第一个枚举常量赋值为零,第二个为1,第三个为2,依此类推。
分配给Level枚举类型中声明的常量的序数值为0到LOW,1到MEDIUM,2到HIGH,以及3到URGENT。
每个枚举常量都有一个与常量的标识符相同的名称。例如,级别枚举类型中的LOW常数的名称为“LOW”。
我们可以分别使用name()和ordinal()方法获取枚举常量的名称和序号。
每个枚举类型都有一个名为values()的静态方法,它按它们在正文中声明的顺序返回一个常量数组。
以下代码打印在Level枚举类型中声明的所有枚举常量的名称和序号。
enum Level { LOW, MEDIUM, HIGH, URGENT; } public class Main { public static void main(String[] args) { for (Level s : Level.values()) { String name = s.name(); int ordinal = s.ordinal(); System.out.println(name + "(" + ordinal + ")"); } } }
上面的代码生成以下结果。
枚举常量的反向查找
我们可以从名称或位置获得枚举常量的引用。使用valueOf()方法。
枚举常量的反向查找区分大小写。
我们可以使用values()方法返回的数组,通过顺序执行反向查找。
values()方法返回的数组中的值的顺序与枚举常量的声明顺序相同。
枚举常量的序数从零开始。
以下代码演示了如何反转查找枚举常量:
enum Level { LOW, MEDIUM, HIGH, URGENT; } public class Main { public static void main(String[] args) { Level low1 = Level.valueOf("LOW"); // A reverse lookup using a name Level low2 = Level.values()[0]; // A reverse lookup using an ordinal System.out.println(low1); System.out.println(low2); System.out.println(low1 == low2); } }
上面的代码生成以下结果。
枚举常量的范围
java.util.EnumSet集合类与枚举类型的枚举常量列表一起使用。
下面的代码演示了如何使用EnumSet类来处理枚举常量的范围。
import java.util.EnumSet; enum Level { LOW, MEDIUM, HIGH, URGENT; } public class Main { public static void main(String[] args) { EnumSet<Level> allLevels = EnumSet.allOf(Level.class); print(allLevels); EnumSet<Level> l = EnumSet.range(Level.LOW, Level.URGENT); print(l); } public static void print(EnumSet<Level> levels) { for (Level d : levels) { System.out.println(d + " "); } } }
上面的代码生成以下结果。
Java 枚举类
Java面向对象设计 - Java枚举类
枚举类型的超类
编译枚举类型时,编译器会创建一个类。
枚举类型可以具有构造函数,字段和方法。枚举类型仅在编译器生成的代码中实例化。
每个枚举类型都隐式地扩展java.lang.Enum类。 Enum类中定义的所有方法都可以与所有枚举类型一起使用。
枚举类
下表列出了在Enum类中定义的方法。
- public final String name()
返回枚举常量的名称。 - public final int ordinal()
返回枚举常量的顺序。 - public final boolean equals(Object other)
如果指定的对象等于枚举常量,则返回true。否则,它返回false。 ==运算符和equals()方法返回相同的结果,当它们用于两个枚举常量。 - public final int hashCode()
返回枚举常量的哈希码值。 - public final int compareTo(E o)
将此枚举常量与指定的枚举常量进行比较。它返回此枚举常量和指定的枚举常量的序数值的差异。 - public final Class getDeclaringClass()
返回声明枚举常量的类的类对象。 - public String toString()
默认情况下,它返回枚举常量的名称,这与name()方法相同。 - public static valueOf(Class enumType,String name)返回指定的枚举类型和名称的枚举常量。
例子
Level lowLevel = Enum.valueOf(Level.class, "LOW")
以下代码显示了如何比较两个枚举常量:
enum Level { LOW, MEDIUM, HIGH, URGENT; } public class Main { public static void main(String[] args) { Level s1 = Level.LOW; Level s2 = Level.HIGH; // s1.compareTo(s2) returns s1.ordinal() - s2.ordinal() int diff = s1.compareTo(s2); if (diff > 0) { System.out.println(s1 + " occurs after " + s2); } else { System.out.println(s1 + " occurs before " + s2); } } }
上面的代码生成以下结果。
Java 枚举方法
Java面向对象设计 - Java枚举方法
因为枚举类型实际上是一个类类型,所以我们可以在枚举类型体中声明一切,我们可以在类体中声明它。
以下代码使用字段,构造函数和方法定义了一个级别枚举。
public enum Level { LOW(30), MEDIUM(15), HIGH(7), URGENT(1); // Declare an instance variable private int levelValue; // Declare a private constructor private Level(int levelValue) { this.levelValue = levelValue; } public int getLevelValue() { return levelValue; } }
上面的代码声明了一个实例变量 levelValue
,它将为每个枚举常量存储一个值。
它还定义了一个私有构造函数,它接受一个int参数。它将其参数的值存储在实例变量中。
我们可以向枚举类型添加多个构造函数。
我们不能向枚举类型添加公共或受保护的构造函数。
级别枚举声明一个公共方法getLevelValue()。
枚举常量声明已更改为
LOW(30), MEDIUM(15), HIGH(7), URGENT(1);
现在每个枚举常量名称后面都跟着括号中的整数值。 LOW(30)是调用int参数类型的构造函数的缩写。
当创建枚举常量时,括号中的值将被传递给我们添加的构造函数。
LOW调用默认的无参数构造函数,而LOW(30)使用参数调用构造函数。
例子
以下代码测试Level枚举类型。它打印常量的名称,它们的序数和它们的下划线值。
enum Level { LOW(30), MEDIUM(15), HIGH(7), URGENT(1); // Declare an instance variable private int levelValue; // Declare a private constructor private Level(int levelValue) { this.levelValue = levelValue; } public int getLevelValue() { return levelValue; } } public class Main { public static void main(String[] args) { for (Level s : Level.values()) { String name = s.name(); int ordinal = s.ordinal(); int underLine = s.getLevelValue(); System.out.println("name=" + name + ", ordinal=" + ordinal + ", underLine=" + underLine); } } }
上面的代码生成以下结果。
Java 枚举主体
Java面向对象设计 - Java枚举主体
将主体添加到枚举常量
我们可以为每个枚举常量添加一个不同的体。身体可以有字段和方法。
枚举常量的主体放在其名称后面的大括号中。
如果枚举常量接受参数,其主体将遵循其参数列表。将主体与枚举常量相关联的语法如下:
<access-modifier> enum <enum-type-name> { ENUM_VALUE1 { // Body for ENUM_VALUE1 goes here }, ENUM_VALUE2 { // Body for ENUM_VALUE2 goes here }, ENUM_VALUE3(arguments-list) { // Body of ENUM_VALUE3 goes here }; // Other code goes here }
例子
下面的代码用body创建了Level枚举类型。
enum Level { LOW("Low Level", 30) { public double getDistance() { return 30.0; } }, MEDIUM("Medium Level", 15) { public double getDistance() { return 15.0; } }, HIGH("High Level", 7) { public double getDistance() { return 7.0; } }, URGENT("Urgent Level", 1) { public double getDistance() { return 1.0; } }; private int levelValue; private String description; private Level(String description, int levelValue) { this.description = description; this.levelValue = levelValue; } public int getLevelValue() { return levelValue; } @Override public String toString() { return this.description; } public abstract double getDistance(); } public class Main { public static void main(String[] args) { for (Level s : Level.values()) { String name = s.name(); String desc = s.toString(); int ordinal = s.ordinal(); int levelValue = s.getLevelValue(); double distance = s.getDistance(); System.out.println("name=" + name + ", description=" + desc + ", ordinal=" + ordinal + ", levelValue=" + levelValue + ", distance=" + distance); } } }
级别枚举有一个抽象方法getDistance()。
每个实例常量都有一个实体为getDistance()方法提供实现。
它重写了Enum类中的toString()方法。
上面的代码生成以下结果。
Java 枚举比较
Java面向对象设计 - Java枚举比较
您可以通过三种方式比较两个枚举常量:
- 使用Enum类的compareTo()方法
- 使用Enum类的equals()方法
- 使用==运算符
Enum类的compareTo()方法比较同一枚举类型的两个枚举常量。它返回两个枚举常量的序数差。如果两个枚举常量相同,则返回零。
例子
以下代码将打印-3,因为LOW(ordinal = 0)和URGENT(ordinal = 3)的序数的差为-3。
负值表示正在比较的常数发生在比较对象之前。
enum Level { LOW, MEDIUM, HIGH, URGENT; } public class Main { public static void main(String[] args) { Level s1 = Level.LOW; Level s2 = Level.URGENT; // s1.compareTo(s2) returns s1.ordinal() - s2.ordinal() int diff = s1.compareTo(s2); System.out.println(diff); } }
上面的代码生成以下结果。
例2
Enum类的equals()方法比较两个枚举常量的相等性。
枚举常量只等于自身。equals()方法可以在不同类型的两个枚举常量上调用。
enum Level { LOW, MEDIUM, HIGH, URGENT; } public class Main { public static void main(String[] args) { Level s1 = Level.LOW; Level s2 = Level.URGENT; System.out.println(s1.equals(s1)); } }
上面的代码生成以下结果。
我们可以使用等于运算符==来比较两个枚举常量的相等性。
==运算符的两个操作数必须是相同的枚举类型。