界说
1)界说
枚举类是Java 5引入的,在Java 5之前,Java并没有内置的枚举类型,只能经过自界说类来完成相似枚举的功用。例如:
public class EnumClass {
public static final int CONSTANT1 = xxx;
public static final int CONSTANT2 = xxx;
public static final int CONSTANT3 = xxx;
...
}
Java 枚举类是一种特别类型的数据结构,一般用来存储界说一些字符串,数字等数据结构。枚举类中的每个常量都称为枚举常量。枚举类在Java中运用关键字enum界说。一般枚举类格式如下:
public enum EnumClass {
CONSTANT1,
CONSTANT2,
CONSTANT3,
...
}
其间,EnumClass为枚举类的称号,CONSTANT1、CONSTANT2、CONSTANT3等为枚举常量的称号。枚举类的引入,供给了一种更简洁、更安全的界说枚举类型的方式。
枚举类能够直接在其他类中引用,例如:
public enum Color {
RED,
GREEN,
BLUE
}
public class ColorUtil {
private ColorUtil() {
}
public static void main(String[] args) {
Color red = Color.RED;
}
}
枚举类是类,所以当然也能够在其他类内部界说:
public class Example {
public enum Color {
RED,
GREEN,
BLUE
}
public static void main(String[] args) {
System.out.println(Color.RED);
}
}
枚举类在内部界说时,能够将其作为内部类来界说,也能够将其作为静态内部类来界说,内部界说的枚举类能够拜访外部类的成员变量和办法,比方:
public class Example {
private static int privateVariable = 10;
public enum Color {
RED, GREEN, BLUE;
public void print() {
System.out.println(name() + " has a value of " + Example.privateVariable);
}
}
public static void main(String[] args) {
Example.Color.RED.print();
}
}
这段代码运转main办法的成果为:
2)内部完成
咱们借助IDEA中的一个反编译分析插件Jadx Class Decompiler反编译刚刚创立的Color枚举类,首要装置插件如下:
装置完成后,右键点击需要反编译的java文件,这里挑选Color.java:
挑选01 分析字节码,能够得到分析成果如下:
能够看到,枚举类是public和final润饰的,这表明它不能像一般的类一样被承继,也能够看到枚举类承继自java.lang.Enum类型,而且界说了public static final润饰的三个实例变量RED GREEN BLUE,这三个实例变量实践都是Color的实例目标。 此外其内部还界说了静态的values办法,它会回来一个包括所有枚举实例的Color[]结构的列表,以及valuesOf(String input)办法,它经过传入对应的枚举常量字符串,回来对应的Color实例。
3)办法与源码
咱们翻阅官方文档能够得知java.lang.Enum包括了如下一些办法(查看Enum类源码也能看到):
其间特有办法应属valuesOf()和ordinal(),valuesOf()刚刚已经阐明,它会回来指定称号的枚举常量,例如:
public enum Color {
RED,
GREEN,
BLUE;
}
Color color = Color.valueOf("GREEN");
ordinal()办法主要是获取枚举量在枚举类中的次序,比方在上面比如中RED排在第一位,ordinal()回来值为0,示例如下:
public static void main(String[] args) {
Color red = Color.RED;
int ordinal = red.ordinal(); // ordinal = 0
}
别的在字节码分析成果中能够看到其实Enum是有结构办法的,可是这个结构办法用户无法调用,只有编译器能够调用,咱们翻阅java.lang.Enum源码能够看到:
别的Enum还针对枚举常量完成了compareTo办法,而且这个compareTo办法默认是依据枚举的ordinal来比照的,也便是依据枚举在枚举类的声明次序来比照的。
高档特性
1)switch用法
咱们知道一般在运用switch进行判别时,能够运用整数、字符串,乃至表达式作为条件,但其实switch也支持枚举,而且不需要运用枚举的引用,代码示例如下:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ColorUtil {
private ColorUtil() {
}
private static String getDescription(Color color) {
switch(color) {
case RED:
return "The color of blood";
case GREEN:
return "The color of grass";
case BLUE:
return "The color of the sky";
default:
return "";
}
}
public static void main(String[] args) {
Color red = Color.RED;
String description = getDescription(red);
System.out.println(description);
}
}
运转能够得到成果如下:
2)自界说传值与结构函数
这个特性我本人经常运用到,首要枚举类中能够界说好特点,然后自界说结构函数,在声明枚举类实例的时分传入对应的特点值,比方在事务中可能用到的isDelete字段,咱们能够界说枚举类如下:
import lombok.Getter;
public enum IsDeleteEnum {
TRUE(1, "是"),
FALSE(0, "否"),
;
//值描述
@Getter
private String desc;
//枚举值
@Getter
private Integer code;
IsDeleteEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
}
这里包括了两个成员变量code和desc,分别代表枚举的值和描述信息。 这个类运用了Lombok库中的@Getter注解,枚举值和称号能够被Getter办法直接拜访。
假如上面这个还是初级版本,那么下面这个高档版本则更为典型和常用,咱们界说了ColorEnum的枚举类,它包括RED、BLUE、GREEN三个枚举值。每个枚举值都有一个值和称号,而且有一个静态的Map用于依据值获取枚举常量。这个类还供给了一个公共的静态办法of(),用于依据给定的值回来对应的枚举常量,假如没有找到则回来null。
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
public enum ColorEnum {
RED(0, "红色"),
BLUE(1, "蓝色"),
GREEN(2, "绿色"),
;
// 枚举值
@Getter
private Integer value;
@Getter
private String name;
private static Map<Integer, ColorEnum> map = new HashMap<>();
static {
for (ColorEnum r : ColorEnum.values()) {
map.put(r.getValue(), r);
}
}
ColorEnum(Integer value, String name) {
this.value = value;
this.name = name;
}
public static ColorEnum of(Integer value) {
return map.getOrDefault(value, null);
}
}
假如我想知道某个常量值x是否包括在枚举类ColorEnum 中,就能够运用of()办法:
public static void main(String[] args) {
System.out.println(ColorEnum.of(0) == null); // false
System.out.println(ColorEnum.of(3) == null); // true
}
运转成果如下:
3)枚举完成笼统办法
枚举中不只能够界说一些整数或是字符串常量,乃至能够从头完成笼统办法,咱们界说了一个枚举类型Weekday,表明一周中的每一天。每个枚举常量都重写了笼统办法doSomething(),并完成了具体的事务逻辑,代码如下:
public enum Weekday {
MONDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Monday");
}
},
TUESDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Tuesday");
}
},
WEDNESDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Wednesday");
}
},
THURSDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Thursday");
}
},
FRIDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Friday");
}
},
SATURDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Saturday");
}
},
SUNDAY {
@Override
public void doSomething() {
System.out.println("Doing something on Sunday");
}
};
// 笼统办法
public abstract void doSomething();
public static void main(String[] args) {
Weekday day = Weekday.MONDAY;
day.doSomething();
}
}
在main函数中,经过Weekday的枚举常量来调用对应的办法,这样能够依据枚举常量来履行不同的操作,大大增加代码的可读性和可维护性。 这段代码履行成果为:
4)枚举注解特点
咱们自界说一个名为ColorInterface的注解用于符号字段。注解界说一个value特点,类型为咱们上文创立的的ColorEnum枚举类型。注解的保存策略为RetentionPolicy.RUNTIME,表明在运转时能够拜访到该注解。
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColorInterface {
ColorEnum value();
}
如下面代码所示,咱们能够经过咱们自界说的ColorInterface注解符号Flower类中的特点。main办法创立了一个Flower目标,运用反射获取Flower类中的Lily字段的注解,然后经过反射获取注解的value特点,也便是咱们的枚举:
import java.lang.reflect.Field;
public class Flower {
@ColorInterface(ColorEnum.BLUE)
private int Lily;
@ColorInterface(ColorEnum.RED)
private int rose;
public static void main(String[] args) throws Exception {
Flower flower = new Flower();
Field field = Flower.class.getDeclaredField("Lily");
ColorInterface annotation = field.getAnnotation(ColorInterface.class);
ColorEnum value = annotation.value();
System.out.println(value);
}
}
代码运转如下:
5)枚举完成接口
Java枚举类还能够完成接口,能够为枚举类型增加更多的办法和行为,然后扩展枚举类的功用,枚举类能够具有更多的灵活性和可扩展性此外。
public interface Animal {
String makeSound();
String getName();
}
public enum Dog implements Animal {
BROWN("Buddy", "Buddy the Brown Dog"),
BLACK("Max", "Max the Black Dog")
;
private String name;
private String sound;
Dog(String name, String sound) {
this.name = name;
this.sound = sound;
}
@Override
public String makeSound() {
return sound;
}
@Override
public String getName() {
return name;
}
public static void main(String[] args) {
Animal dog = Dog.BLACK;
System.out.println(dog.getName()); // 输出: Max
System.out.println(dog.makeSound()); // 输出: Max the Black Dog
}
}
运转成果如下!:
总结
枚举类是Java中的原始类型之一,能够作为办法参数和回来值。枚举类能够经过类内的枚举常量表明特定的值。本文从源码和字节码完成的角度对枚举类的原理做了论述,而且还展示了枚举类的多种高档用法,枚举类不只能够像一般的类常量一样进行拜访和运用,而且能够进行多态操作,不同的枚举常量能够有不同的办法完成,而且能够作为办法的参数和回来值。 因此枚举类有如下长处:
1.进步代码的可读性。枚举类的命名规范明晰明晰,能够更直观地表达代码的含义,进步代码的可读性
2.更简单的调试和维护。枚举类中的办法和变量都在一个当地,便利调试和维护。
3.更好的类型安全性。运用枚举类能够供给更好的类型安全性,避免了运用整数或其他类型的过错。
4.能够便利的进行多态操作:枚举类支持办法的重写和多态,能够便利的扩展功用。