下面这段在开始的截图有出现
public static com.example.demo.enu.DemoEnum[] values(); Code: // 获取静态域 $VALUES的值 0: getstatic #1 // Field $VALUES:[Lcom/example/demo/enu/DemoEnum; // 调用clone()方法 3: invokevirtual #2 // Method "[Lcom/example/demo/enu/DemoEnum;".clone:()Ljava/lang/Object; // 类型检查 6: checkcast #3 // class "[Lcom/example/demo/enu/DemoEnum;" // 返回clone()后的方法 9: areturn上面之所以要使用clone(),是避免调用values(),将内部的数组暴露出去,从而有被修改的分险,也存在线程安全问题
后面一处,就是在static{}块最后那部分
从这两处反编译后的字节码,我们能很清晰明了的知道这个套路了
编译器自己给我们强行插入一个静态方法values(),而且还有一个 T[] $VALUES数组,不过这个静态域在源码没找到,估计是编译器编译时加进去的
到这里还没完,我们再来看个有意思的java.lang.Class#getEnumConstantsShared,在java.lang.Class中有这么个方法,访问修饰符是default,包访问级别的
T[] getEnumConstantsShared() { if (enumConstants == null) { if (!isEnum()) return null; try { // 看这里 看这里 看这里 final Method values = getMethod("values"); java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { values.setAccessible(true); return null; } }); @SuppressWarnings("unchecked") // 还有这里 这里 这里 T[] temporaryConstants = (T[])values.invoke(null); enumConstants = temporaryConstants; } // These can happen when users concoct enum-like classes // that don't comply with the enum spec. // 这里是一个安全保护,防止自己写了一个类似enum的类,但是没有values方法 catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) { return null; } } return enumConstants; }我们的valuesOf方法,在底层就是调用它来实现的,很遗憾的是,这个valuesOf方法,仅仅实现了通过枚举类型的name来查找对应的枚举值。
也就是我们只能通过变量名 name = "ONE"这种方式,来查找到DemoEnum.ONE这个枚举值
后记以前因为枚举用的少,也就仅仅停留在使用的层面,其实在使用的过程中,也有很多疑惑产生,但是并没有真正像现在这样去深究它的实现。
也许是之前动力不足,也许是对未知的恐惧,也许是其他方面的知识准备还不够。
总之,到现在才算真的理解Java枚举
关于其他方面的知识准备不足,这个我觉得还是值得说一下的,之前我就写过一次说这个事的,因为有些知识点,它并不是孤立的,是网状的,我们在看某一个点的时候,往往就像在一个蜘蛛网上,但是这个网上太多我们不知道的东西了,所以就很容易出现去不断的补充和它相关的知识点的情况,这个时候就会很累,而且,你最开始想学的那个知识点,也没怎么搞懂。