引言:枚举类;补充了一些额外知识点
枚举类 为什么要使用枚举类?
安全性 (使用枚举类不会被反射获取,不可以与其他类型的值进行比较,防止错误)
易读性 (枚举类比原本使用数字可以携带更多的信息,尤其是在日志记录时,更加容易)
Enum类的核心API 所有枚举类,默认继承自java.lang.Enum
类 ,该类有以下几个方法
1 2 3 String name () String toString () int ordinal ()
注意:
尽量使用name()
方法来返回字符串等效串,而不去使用toString
为什么要使用name()
?
因为你不能保证toString
没有被重写!
导致此枚举类在序列化时有可能使字符串失去等效性 ,而使用name()
就没有这种情况
一个枚举的Demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public enum Color { RED("红色" , 1 ), GREEN("绿色" , 2 ), BLANK("白色" , 3 ), YELLO("黄色" , 4 ); private String name; private int index; private Color (String name, int index) { this .name = name; this .index = index; } @Override public String toString () { return "Color{" + "name='" + name + '\'' + ", index=" + index + '}' ; } }
测试一下API会返回什么?
1 2 3 4 Color color = Color.BLANK; System.out.println(color.name()); System.out.println(color.toString()); System.out.println(color.ordinal());
枚举类的特点
枚举类继承自java.lang.Enum
(因此枚举类不能继承其他类,但是可以实现接口)
无法使用new
创建实例(因为构造方法是私有的)
定义的每个实例都是引用类型的唯一实例(唯一一个安全的构造单例模式的方法)
可以在switch
语句中使用
枚举类的本质 我们自己建立的枚举类
1 2 3 public enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT; }
在被编译器编译后是这样
1 2 3 4 5 6 7 8 9 10 11 12 13 public final class Weekday extends Enum { public static final Weekday SUN = new Weekday(); public static final Weekday MON = new Weekday(); public static final Weekday TUE = new Weekday(); public static final Weekday WED = new Weekday(); public static final Weekday THU = new Weekday(); public static final Weekday FRI = new Weekday(); public static final Weekday SAT = new Weekday(); private Color () {} }
由于ordinal()
方法依赖于排序树,所以改变枚举类常量的顺序就会发生变化,不利于程序的鲁棒性
建议枚举类代码写为
1 2 3 4 5 6 7 8 public enum Weekday { SUN(0 ), MON(1 ), TUE(2 ), WED(3 ), THU(4 ), FRI(5 ), SAT(6 ); public final int dayValue; Weekday(int dayValue) { this .dayValue = dayValue; } }
判断枚举常量的名字,要始终使用name()方法,绝不能调用toString()!
在switch语句中使用 switch()
语句支持的类型有:byte char short int
及其包装类 、以及枚举类 和String
有关switch
这方面推荐博客CSDN博主 由零开始Leon
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Weekday day = Weekday.SUN; switch (day) {case MON:case TUE:case WED:case THU:case FRI: System.out.println("Today is " + day + ". Work at office!" ); break ; case SAT:case SUN: System.out.println("Today is " + day + ". Work at home!" ); break ; default : throw new RuntimeException("cannot process " + day);
枚举的values()
方法 枚举类都有一个values
方法,但注意,这个方法并不来自父类Enum,而是编译器增加的一个方法
The compiler automatically adds some special methods when it creates an enum. For example, they have a static values
method that returns an array containing all of the values of the enum in the order they are declared. (Oracle官方文档 )
翻译:编译器在创建enum时,会自动添加一些方法。比如values
静态方法,会返回一个该枚举类型的数组
工作中经常会遇到一个枚举类,需要通过Int获取他的String(或是相反)的情况,这里给出一个模板 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public enum EnumTemplate { CREATE(0 ,"create" ), TOUCH(1 ,"touch" ), SUBMIT(2 , "submit" ); private String tag; private Integer id; EnumTemplate(Integer id, String tag) { this .tag = tag; this .id = id; } public static String getNameById (Integer id) { for (EnumTemplate value : values()) { if (value.id.equals(id)){ return value.tag; } } return "" ; } public static Integer getIdByName (String name) { return Arrays.stream(values()) .collect(Collectors.toList()) .stream() .filter(x -> name.equals(x.tag)) .map(EnumTemplate::getId) .findFirst().orElse(0 ); } public String getTag () { return tag; } public Integer getId () { return id; } }
注意 :工作强烈建议使用普通方法 而不是流式写法,效率差太多了 (差距一百多倍)。
枚举的更多写法 接口的内部枚举 有时候我们会遇到这种情况,枚举有了分类,比如:腾讯有QQ与微信,QQ有QQ登录的和平精英、王者荣耀,微信同样也有,但是我们想用枚举标识这两种不同的账号,我们可以如此创建这个枚举类。
同一个接口Tencent
下,实现了两个枚举类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public interface Tencent { enum WX { WX_WZRY(0 , "王者荣耀" ), WX_HPJY(1 , "和平精英" ); private Integer id; private String name; WX(Integer id, String name) { this .id = id; this .name = name; } public Integer getId () { return id; } public String getName () { return name; } } enum QQ { QQ_WZRY(0 , "王者荣耀" ), QQ_HPJY(1 , "和平精英" ); private Integer id; private String name; QQ(Integer id, String name) { this .id = id; this .name = name; } public Integer getId () { return id; } public String getName () { return name; } } }
在调用时,我们需要通过接口名调用,才能拿到想要的数据:
1 TencentEnum.WX.WX_HPJY.getName();
接口实现抽象方法 枚举类可以有抽象方法,并且需要在实例中实现。
假设现在需要给和平精英的玩家发红包,但是发的个数不同,就可以这么写:
(但这种写法具体有什么好处,有待考究)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public enum TencentEnum2 { WX_HPJY(0 , "和平精英" ){ private final Integer num = 100 ; @Override public int sendHongBao () { return num; } }, QQ_HPJY(1 , "和平精英" ){ private final Integer num = 1 ; @Override public int sendHongBao () { return num; } }, WX_WZRY(2 , "王者荣耀" ){ @Override public int sendHongBao () { return 0 ; } }; private Integer id; private String name; abstract public int sendHongBao () ; TencentEnum2(Integer id, String name) { this .id = id; this .name = name; } }
参考材料: 廖雪峰官方网站 官方APICSDN博主 由零开始Leon