网站首页 > 精选教程 正文
枚举特性
我们先来写一个枚举
public enum TestEnum {
//TEACHER 老师;STUDENT 学生;PARENT 父母
TEACHER,STUDENT,PARENT
}
然后编译成class文件,再反编译class文件。
PS E:\Study\code\demo\src\main\java\com\lvshen\demo\enumtest> javac .\TestEnum.java
PS E:\Study\code\demo\src\main\java\com\lvshen\demo\enumtest> javap -p .\TestEnum.class
Compiled from "TestEnum.java"
//代码区
public final class com.lvshen.demo.enumtest.TestEnum extends java.lang.Enum<com.lvshen.demo.enumtest.TestEnum> {
public static final com.lvshen.demo.enumtest.TestEnum TEACHER;
public static final com.lvshen.demo.enumtest.TestEnum STUDENT;
public static final com.lvshen.demo.enumtest.TestEnum PARENT;
private static final com.lvshen.demo.enumtest.TestEnum[] $VALUES;
public static com.lvshen.demo.enumtest.TestEnum[] values();
public static com.lvshen.demo.enumtest.TestEnum valueOf(java.lang.String);
//构造函数
private com.lvshen.demo.enumtest.TestEnum();
static {};
}
我们发现枚举有这几个特性:
“
(1)枚举TestEnum被final修饰,并且默认继承了Enum类。因此不能再继承其他的类。
(2)枚举的构造函数是private修饰的,所以不能通过构造函数获取对象。
(3)枚举的属性是static修饰的,可以通过枚举直接调用属性。
(4)valueOf(java.lang.String)可以通过枚举的名称获取对应的实例。
”
还有一个重要的特性,对于(2)虽然不能直接获取构造对象,你可能会有疑问,我反射暴力获取可以吗?答案是不可以。我们看看反射是怎么做的。
Class<?> aClass = Class.forName("xx.xx.xx");
Constructor<?> constructor = aClass.getDeclaredConstructor(String.class);
TestEnum test = (TestEnum) constructor.newInstance("");
我们来看看newInstance。
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
如果是枚举,你想暴力反射获取对象,直接抛异常。
我们能用枚举做什么
消除烦人的if/else
当你代码中的if/else过多的时候,会提高你代码的复杂度,如果你们公司对sonar异味有要求,肯定被if/else困扰过。
我们可以用枚举消除if/else,使用场景如下:
if ("PANDA".equals(type)) {
System.out.println("吃竹子");
} else if("CAT".equals(type)) {
System.out.println("吃鱼");
} else if("MONKEY".equals(type)) {
System.out.println("吃香蕉");
}
当输入type,输出对应结果。例如当type = "CAT"时,输出"吃鱼"。你肯定会想到用上面的if/else方法。我们用枚举怎么做呢?
首先创建接口,定义通用方法
public interface Common {
//吃
String eat();
}
创建枚举实现这个方法
public enum AnimalEnum implements Common {
PANDA {
@Override
public String eat() {
return "吃竹子";
}
},
CAT {
@Override
public String eat() {
return "吃鱼";
}
},
MONKEY{
@Override
public String eat() {
return "吃香蕉";
}
}
}
然后调用
String type = "CAT";
String eat = AnimalEnum.valueOf(type).eat();
System.out.println(eat);
当type = "CAT"时,输出"吃鱼"。至此我们消除了if/else。
用枚举实现单列
《 Effective Java》作者大力推荐的方式。
这种方式不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化和反射攻击重新创建新的对象,绝对防止多次实例化。
我们来看代码
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance() {
return INSTANCE;
}
}
我们起两个线程来测试
public void test1() {
EnumSingleton instance1 = EnumSingleton.INSTANCE.getInstance();
EnumSingleton instance2 = EnumSingleton.INSTANCE.getInstance();
System.out.println(instance1 == instance2);
}
运行结果为True。
由之前的反编译可知,属性INSTANCE 被声明为static的。枚举实现实例化时是线程安全。
Java 规范中规定,每一个枚举类型及其定义的枚举变量在 JVM 中都是唯一的,并且在枚举类型的序列化和反序列化上,Java 做了特殊的规定。在序列化的时候 Java 仅仅是将枚举对象的 name 属性输出到结果中,反序列化的时候则是通过 java.lang.Enum 的 valueOf() 方法来根据名字查找枚举对象,因此反序列化后的实例也会和之前被序列化的对象实例相同。
不过个人觉得想要实现单例就要将这个对象设计成枚举类型的,虽然安全可靠,但还是不优雅。
EnumMap
如果你需要存储key-value格式的数据,并且这个key来源于一个枚举类,那么使用EnumMap而不是HashMap。EnumMap拥有更优良的性能。
public enum TestEnum {
TEACHER,STUDENT,PARENT
}
//使用
EnumMap<TestEnum, String> enumMap = new EnumMap<>(TestEnum.class);
enumMap.put(TestEnum.TEACHER,"教书");
enumMap.put(TestEnum.STUDENT,"学习");
enumMap.put(TestEnum.PARENT,"培育小孩");
String result = enumMap.get(TestEnum.PARENT);
System.out.println(result);
我们可以通过EnumMap给枚举的成员属性赋予特定行为。如上代码,result = "培育小孩"。
EnumSet
public enum TestEnum {
TEACHER,STUDENT,PARENT
}
我们定义了枚举TestEnum,如何获取所有成员属性?这是可以使用EnumSet。
EnumSet enumSet = EnumSet.allOf(TestEnum.class);
System.out.println(enumSet);
控制台打印
[TEACHER, STUDENT, PARENT]
与HashSet相比,EnumSet性能更优良。
猜你喜欢
- 2024-11-09 Java基础入门要学哪些 怎么掌握反射和枚举
- 2024-11-09 谈谈枚举的新用法--java java枚举类型有什么用
- 2024-11-09 Java面试基础回顾16-枚举 java面试基础知识点
- 2024-11-09 实际工作中推荐使用java枚举类型,提高开发效率#编程
- 2024-11-09 java枚举enumeration java枚举根据value获取key
- 2024-11-09 大年初二来简单聊聊java中枚举类的前世今生
- 2024-11-09 干货 | 一文搞定Python 枚举 python 枚举遍历
- 2024-11-09 Scala学习九之枚举和Trait了解 枚举compareto
- 2024-11-09 java中的enum第一期:enum存在的意义
- 2024-11-09 Scala基础学习九之枚举和Trait了解
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)