摘要:还为该枚举类生成了一个方法,这个方法就是本文要讲的方法,我们来具体看下其操作获取静态变量。
Java中的枚举类是我们平时写代码时经常会用到的一个类型,在我们创建枚举类之后,Java会默认在该类中为我们生成values、valueof 等方法。
但你知道吗,values方法可是个拷贝操作。
写个例子验证下:
$ cat Type.java public enum Type { T1, T2, ; public static void main(String[] args) { System.out.println(Type.values() == Type.values()); } } $ java Type.java false
如果values方法不是拷贝操作的话,那两次方法调用返回的对象应该是一样的,但结果却输出了false,可见该方法应该就是拷贝操作。
有同学可能会发现,我们没编译,直接执行的java Type.java,而且还成功了,java不是要先编译后才能执行吗?
有关这个问题,可以看我上一篇文章:Java也可以不用编译直接执行了?
继续回到本文的话题。
上文我们说到,values方法是拷贝操作,但这只是我们的猜测,有什么证据能明确证明吗?
我们看下上面类对应的字节码:
$ javac Type.java $ javap -c -p Type Compiled from "Type.java" public final class Type extends java.lang.Enum{ public static final Type T1; public static final Type T2; private static final Type[] $VALUES; public static Type[] values(); Code: 0: getstatic #1 // Field $VALUES:[LType; 3: invokevirtual #2 // Method "[LType;".clone:()Ljava/lang/Object; 6: checkcast #3 // class "[LType;" 9: areturn # 省略无关字节码 # static {}; Code: 0: new #4 // class Type 3: dup 4: ldc #10 // String T1 6: iconst_0 7: invokespecial #11 // Method " ":(Ljava/lang/String;I)V 10: putstatic #12 // Field T1:LType; 13: new #4 // class Type 16: dup 17: ldc #13 // String T2 19: iconst_1 20: invokespecial #11 // Method " ":(Ljava/lang/String;I)V 23: putstatic #14 // Field T2:LType; 26: iconst_2 27: anewarray #4 // class Type 30: dup 31: iconst_0 32: getstatic #12 // Field T1:LType; 35: aastore 36: dup 37: iconst_1 38: getstatic #14 // Field T2:LType; 41: aastore 42: putstatic #1 // Field $VALUES:[LType; 45: return }
由字节码可见,javac自动为我们生成了很多东西,其中就包括一个static代码块。
该代码块的大致逻辑是:
创建类型为Type的实例,new Type("T1", 0),赋值给静态变量T1。
创建类型为Type的实例,new Type("T2", 1),赋值给静态变量T2。
创建类型为Type数组,并将静态变量T1、T2依次放到数组中,然后再将该数组赋值给静态变量 $VALUES。
javac还为该枚举类生成了一个values方法,这个values方法就是本文要讲的方法,我们来具体看下其操作:
获取静态变量$VALUES。
调用$VALUES的clone方法。
将clone方法返回的对象强转成Type数组。
返回该数组。
由此我们可以看到,values方法的确是拷贝操作。
上文我们说到,values等方法是javac动态生成的,是这样吗?
我们还是通过源码来确认下这个疑问。
// com.sun.tools.javac.comp.TypeEnter.MembersPhase private void addEnumMembers(JCClassDecl tree, Envenv) { ... // public static T[] values() { return ???; } JCMethodDecl values = make. MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), names.values, valuesType, List.nil(), List.nil(), List.nil(), // thrown null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), null); ... }
该方法向Enum类里添加了values方法,但还没有方法体。
// com.sun.tools.javac.comp.Lower private void visitEnumDef(JCClassDecl tree) { ... Symbol valuesSym = lookupMethod(tree.pos(), names.values, tree.type, List.nil()); ... if (useClone()) { // return (T[]) $VALUES.clone(); JCTypeCast valuesResult = make.TypeCast(valuesSym.type.getReturnType(), make.App(make.Select(make.Ident(valuesVar), syms.arrayCloneMethod))); valuesBody = List.of(make.Return(valuesResult)); } else { // template: T[] $result = new T[$values.length]; ... // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length); ... // template: return $result; ... } ... }
该方法向Enum类的values方法里添加了方法体。
怎么样,现在一切都非常明朗了吧,values方法会拷贝数组$VALUES的值,然后返回给我们。
希望能对大家有所帮助。
完。
更多原创文章,请关注我微信公众号:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/76128.html
摘要:原文你真的会克隆对象吗开始之前在开始聊克隆之前,我们还是先来看看数据类型。值通过函数生成,是独一无二的。同时,中规定了对象的属性名有两种类型,一种是字符串,另一种就是类型。返回一个数组,包含对象自身的所有属性的键名。 原文:你真的会克隆对象吗 开始之前 在开始聊克隆之前,我们还是先来看看js数据类型。js的数据类型分为基本数据类型和复杂数据类型。 基本数据类型:Number、Bool...
摘要:它接受任意数量的源对象,枚举它们的所有属性并分配给。所以现在怎么办有几种方法可以创建一个对象的深拷贝。为了防止发生任何意外,请使用而不是。我想测量哪种方法是最高性能的。图表以下是,和中不同技术的性能。 原文:Deep-copying in JavaScript - DasSur.ma 如何在 JavaScript 中拷贝一个对象?对于这个很简单的问题,但是答案却不简单。 引用传值 在...
摘要:介一回,偶们来聊一下用中的类,有些盆友可能用过或者的,知道语法糖,可是在中并没有,中需要用到构造函数来模拟类。而且要注意一点,构造函数没有语句,是自动返回。 本回内容介绍 上一回聊到JS的Function类型,做了柯里化,数组去重,排序的题。 介一回,偶们来聊一下用JS中的类,有些盆友可能用过ES6或者TypeScript的,知道Class语法糖,可是在ES5中并没有,ES5中需要用到...
摘要:网站的面试专题学习笔记非可变性和对象引用输出为,前后皆有空格。假定栈空间足够的话,尽管递归调用比较难以调试,在语言中实现递归调用也是完全可行的。栈遵守规则,因此递归调用方法能够记住调用者并且知道此轮执行结束之返回至当初的被调用位置。 ImportNew 网站的Java面试专题学习笔记 1. 非可变性和对象引用 String s = Hello ; s += World ; s.tr...
摘要:木易杨注意原始类型被包装为对象木易杨原始类型会被包装,和会被忽略。木易杨原因在于时,其属性描述符为不可写,即。木易杨解决方法也很简单,使用我们在进阶期中介绍的就可以了,使用如下。 引言 上篇文章介绍了赋值、浅拷贝和深拷贝,其中介绍了很多赋值和浅拷贝的相关知识以及两者区别,限于篇幅只介绍了一种常用深拷贝方案。 本篇文章会先介绍浅拷贝 Object.assign 的实现原理,然后带你手动实...
阅读 3184·2021-11-15 11:37
阅读 2427·2021-09-29 09:48
阅读 3769·2021-09-22 15:55
阅读 2982·2021-09-22 10:02
阅读 2611·2021-08-25 09:40
阅读 3205·2021-08-03 14:03
阅读 1671·2019-08-29 13:11
阅读 1550·2019-08-29 12:49