作业16:java枚举类的秘密
- JAVA代码
public enum EnumTest {
HELLO,WORLD
}
- 字节码
public final class EnumTest extends java.lang.Enum<EnumTest> {
public static final EnumTest HELLO;
public static final EnumTest WORLD;
public static EnumTest[] values();
Code:
0: getstatic #1 // Field $VALUES:[LEnumTest;
3: invokevirtual #2 // Method "[LEnumTest;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LEnumTest;"
9: areturn // 从当前方法返回对象引用
// 调用了(EnumTest)java.lang.Enum.valueOf(EnumTest.class,String)
public static EnumTest valueOf(java.lang.String);
Code:
0: ldc #4 // class EnumTest
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class EnumTest
9: areturn
static {};
Code:
0: new #4 // class EnumTest
3: dup
4: ldc #7 // String HELLO
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field HELLO:LEnumTest;
13: new #4 // class EnumTest
16: dup
17: ldc #10 // String WORLD
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field WORLD:LEnumTest;
26: iconst_2
27: anewarray #4 // class EnumTest, 创建一个引用型(如类,接口,数组)的数组,并将其引用值压入栈顶
30: dup
31: iconst_0
32: getstatic #9 // Field HELLO:LEnumTest;获取指定类的静态域,并将其值压入栈顶
35: aastore
36: dup
37: iconst_1
38: getstatic #11 // Field WORLD:LEnumTest;
41: aastore
42: putstatic #1 // Field $VALUES:[LEnumTest;用栈顶的值为指定的类的静态域赋值
45: return
}
- 参考源码实现的枚举(没有继承 java.lang.Enum):
public final class MyEnum {
private final String s;
private MyEnum(String s) {
this.s = s;
}
public static final MyEnum HELLO = new MyEnum("HELLO");
public static final MyEnum WORLD = new MyEnum("WORLD");
private static volatile MyEnum[] $VALUES;
static {
Field[] fields = MyEnum.class.getFields();
List<Field> list = Arrays.asList(fields);
$VALUES = list.stream().map(field -> {
try {
return field.get(MyEnum.class);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}).collect(Collectors.toList()).toArray(new MyEnum[fields.length]);
}
public static MyEnum[] values() {
return $VALUES;
}
public static MyEnum valueOf(String name) throws NoSuchFieldException, IllegalAccessException {
Class<MyEnum> clazz = MyEnum.class;
Field field = clazz.getField(name);
return (MyEnum) field.get(clazz);
}
@Override
public String toString() {
return s;
}
}
- java.lang.Enum类
// Enum 不能直接被继承
// 下列省略部分代码
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
private final int ordinal;
public final String name() {
return name;
}
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
// 比较ordinal值,用于排序
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass(); // 获取当前类的Class
Class<?> zuper = clazz.getSuperclass(); // 获取当前类的父类
// 如果父类是Enum.class,则返回当前类的Class,否则返回父类的Class
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null) return result;
// 为什么不先判断name是否等于null?
if (name == null) throw new NullPointerException("Name is null");
throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name);
}
public final boolean equals(Object var1) {
return this == var1;
}
}
public final class Class<T>{
private transient volatile Map<String, T> enumConstantDirectory;
// 简单的说生成枚举Map:{"HEELO":EnumTest.HELLO,"WORLD":EnumTest.WORLD}
Map<String, T> enumConstantDirectory() {
Map<String, T> directory = enumConstantDirectory;
if (directory == null) {
T[] universe = getEnumConstantsShared();
if (universe == null)
throw new IllegalArgumentException(getName() + " is not an enum type");
directory = new HashMap<>(2 * universe.length);
for (T constant : universe) {
directory.put(((Enum<?>)constant).name(), constant);
}
enumConstantDirectory = directory;
}
return directory;
}
private transient volatile T[] enumConstants;
T[] getEnumConstantsShared() {
T[] constants = enumConstants;
if (constants == null) {
// 非Enum 直接返回null
if (!isEnum()) return null;
try {
final Method values = getMethod("values");
// 提升访问修饰
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public Void run() {
values.setAccessible(true);
return null;
}
});
// 反射调用values方法,得到枚举数组
@SuppressWarnings("unchecked")
T[] temporaryConstants = (T[])values.invoke(null);
enumConstants = constants = temporaryConstants;
}catch (InvocationTargetException | NoSuchMethodException |IllegalAccessException ex) {
return null;
}
}
return constants;
}
public boolean isEnum() {
// 返回此类或接口以整数编码的 Java语言修饰符,如:public private protected、enum等。
// 如果modifers有enum修饰语ENUM &操作将得到ENUM,不等于0。
return (this.getModifiers() & ENUM) != 0 &&
this.getSuperclass() == java.lang.Enum.class;
}
}
- 测试
Class<?> aClass = EnumTest.HELLO.getClass();
System.out.println(aClass); // class EnumTest
System.out.println(aClass.getSuperclass()); // class java.lang.Enum
- 结论
- 枚举类是一个普通的java类,enum类型只是java的语法糖,编译器帮助开发人员转化为Eunm类。
- 枚举类继承了java.lang.Enum类,valueOf和values方法继承自Enum类。
- java.lang.Enum类不能被直接继承,所以自己实现的valueOf的实现采用了反射获取字段。
- java.lang.Enum类的valueOf实现采用了Class类反射和内部的map缓存。
作业16:java枚举类的秘密的更多相关文章
- Java枚举类在生产环境中的使用方式
前言 Java枚举在项目中使用非常普遍,许多人在做项目时,一定会遇到要维护某些业务场景状态的时候,往往会定义一个常量类,然后添加业务场景相关的状态常量.但实际上,生产环境的项目中业务状态的定义大部 ...
- Java基础15:深入剖析Java枚举类
更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...
- Java枚举类使用和总结
1.枚举类使用情况一: package com.bie.util; import java.util.HashMap; import java.util.Map; /** * * @author bi ...
- Java 枚举类 详解
1.枚举是什么? Java中的枚举其实是一种语法糖,在 JDK 1.5之后出现,用来表示固定且有限个的对象.比如一个季节类有春.夏.秋.冬四个对象:一个星期有星期一到星期日七个对象.这些明显都是固定的 ...
- 夯实Java基础系列14:深入理解Java枚举类
目录 初探枚举类 枚举类-语法 枚举类的具体使用 使用枚举类的注意事项 枚举类的实现原理 枚举类实战 实战一无参 实战二有一参 实战三有两参 枚举类总结 枚举 API 总结 参考文章 微信公众号 Ja ...
- Java枚举类、注解和反射
本文主要介绍的是枚举类,注解和反射.还有一些基础知识:static,基本数据类型,运算符优先级放在文中,以便查阅复习. 其中牵扯到泛型的部分,可参考本人的另一篇博客:(Collection, List ...
- Java枚举类与注解详解——一篇文章读懂枚举类与注解详
目录 一.枚举类 ① 自定义枚举类 ② enum关键字定义枚举类 ③ enum 枚举类的方法 ④ enum 枚举类实现接口 二.注解 ① 生成文档相关注解 ②注解在编译时进行格式检查 ③注解跟踪代码的 ...
- Java 枚举类
如果要定义一个枚举类: public enum Size { SAMLL, MEDIUM, LARGE, EXTRA, EXTRA_LARGE}; 实际上,这个声明定义的类型是一个类,它刚好有4个实例 ...
- java 枚举类 enum 总结
枚举定义: enum是计算机编程语言中的一种数据类型.枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量 ...
随机推荐
- DELPHI正则表达式
DELPHI正则表达式 1)下载源码 官方网站: http://www.regular-expressions.info/delphi.html 直接下载: http://www.regula ...
- ISO/IEC 9899:2011 条款6.4.1——关键字
6.4.1 关键字 语法 1.以下为关键字: auto break case char const continue default do double ...
- iOS8.0如何使用Touch ID来做验证
对于Objective-C而言,只要几行代码即可搞定. 比如: #import <LocalAuthentication/LocalAuthentication.h> - (void)vi ...
- 23Flutter FloatingActionButton实现类似闲鱼App底部导航凸起按钮:
/* 一.Flutter FloatingActionButton介绍 FloatingActionButton简称FAB,可以实现浮动按钮,也可以实现类型闲鱼app的底部凸起导航. child:子视 ...
- spring boot打开tomcat的access日志
spring boot虽说内置了tomcat,但打出来的是jar包而非war包,更没有access日志,那么如何打开access日志呢?只需在application.properties中加入相关配置 ...
- c# 调用mysql数据库验证用户名和密码
使用mysql数据库验证用户名和密码时,如果用户名是中文,一直查不到数据 需要把app.config 中修改为 数据库统一设置utf8编码格式,连接数据库的时候设置编码Charset=utf8可以避免 ...
- [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /usr/local/nginx/conf/nginx.conf:1
带有sudo 权限执行就可以了
- MySQL 5.7 源码中的目录结构
MySQl Server的源码可以直接去Github浏览. 这里我们选择5.7版本的:https://github.com/mysql/mysql-server/tree/5.7 也可以通过: git ...
- 安装android sdk,后出现导出错误,提示命令行找不到解决方案
The steps. Rename android sdk tool folder : [Your Android SDK root]/tools -> toolsXXXX Download S ...
- 【c# 学习笔记】委托链的使用
委托链其实就是委托类型,只是委托链把多个委托链接在一起而已,也就是说,我们把链接了多个方法的委托称为委托链或多路广播委托.如下: public delegate void DelegateTest() ...