作业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是计算机编程语言中的一种数据类型.枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量 ...
随机推荐
- 判断 js 类型的方式
1. typeof 可以判断出'string','number','boolean','undefined','symbol'但判断 typeof(null) 时值为 'object'; 判断数组和对 ...
- OpenJudge计算概论-苹果和虫子
/*======================================================== 苹果和虫子 总时间限制: 1000ms 内存限制: 65536kB 描述 你买了一 ...
- 解决Visual Studio:"无法导入以下密钥文件: xxxx.pfx,该密钥文件可能受密码保护"
[解决方法] 从开始菜单找到并打开Visual Studio 命令提示(2010):开始->Microsoft Visual Studio 2010->Visual Studio Tool ...
- angular项目目录结构分析
详情查看:https://www.angular.cn/guide/file-structure app.module.ts 定义 AppModule, 这个根模块会告诉 Angular 如何组装该应 ...
- 使用editplus等编程工具时UTF-8编码去掉BOM头方法(转载备查)
Unicode规范中有一个BOM的概念.BOM——Byte Order Mark,就是字节序标记.在这里找到一段关于BOM的说明: 在UCS 编码中有一个叫做"ZERO WI ...
- labelimg data
<annotation> <folder>img_data_box_1500</folder> <filename>798.jpg</filena ...
- javascript中的Error对象
在javascript中一旦代码解析或运行时发生错误,javascript引擎就会自动产生并抛出一个Error对象的实例,然后整个程序就中断在发生错误的地方. Error对象的实例有三个基本的属性: ...
- Django和Flask这两个框架对比
Flask 在 Django 之后发布,现阶段有大量的插件和扩展满足不同需要 Django发布于2005年,Flask创始于2010年年中. Django功能大而全,Flask只包含基本的配置, D ...
- python高级知识
网络udp socket的作用 进程指的是:运行的程序以及运行时用到的资源这个整体称之为进程 socket(简称 套接字) 是最通用的进程间通信的一种方式 创建socket import socket ...
- python基础之内置模块(二)
configparser configparser用来对特定格式的文件进行解析处理,比如ha-proxy,rsync,samba配置文件等等均可.来个简单的文件先看下: [section1] #节点 ...