摘要:還為該枚舉類生成了一個(gè)方法,這個(gè)方法就是本文要講的方法,我們來具體看下其操作獲取靜態(tài)變量。
Java中的枚舉類是我們平時(shí)寫代碼時(shí)經(jīng)常會用到的一個(gè)類型,在我們創(chuàng)建枚舉類之后,Java會默認(rèn)在該類中為我們生成values、valueof 等方法。
但你知道嗎,values方法可是個(gè)拷貝操作。
寫個(gè)例子驗(yàn)證下:
$ 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方法不是拷貝操作的話,那兩次方法調(diào)用返回的對象應(yīng)該是一樣的,但結(jié)果卻輸出了false,可見該方法應(yīng)該就是拷貝操作。
有同學(xué)可能會發(fā)現(xiàn),我們沒編譯,直接執(zhí)行的java Type.java,而且還成功了,java不是要先編譯后才能執(zhí)行嗎?
有關(guān)這個(gè)問題,可以看我上一篇文章:Java也可以不用編譯直接執(zhí)行了?
繼續(xù)回到本文的話題。
上文我們說到,values方法是拷貝操作,但這只是我們的猜測,有什么證據(jù)能明確證明嗎?
我們看下上面類對應(yīng)的字節(jié)碼:
$ 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 # 省略無關(guān)字節(jié)碼 # 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 }
由字節(jié)碼可見,javac自動為我們生成了很多東西,其中就包括一個(gè)static代碼塊。
該代碼塊的大致邏輯是:
創(chuàng)建類型為Type的實(shí)例,new Type("T1", 0),賦值給靜態(tài)變量T1。
創(chuàng)建類型為Type的實(shí)例,new Type("T2", 1),賦值給靜態(tài)變量T2。
創(chuàng)建類型為Type數(shù)組,并將靜態(tài)變量T1、T2依次放到數(shù)組中,然后再將該數(shù)組賦值給靜態(tài)變量 $VALUES。
javac還為該枚舉類生成了一個(gè)values方法,這個(gè)values方法就是本文要講的方法,我們來具體看下其操作:
獲取靜態(tài)變量$VALUES。
調(diào)用$VALUES的clone方法。
將clone方法返回的對象強(qiáng)轉(zhuǎn)成Type數(shù)組。
返回該數(shù)組。
由此我們可以看到,values方法的確是拷貝操作。
上文我們說到,values等方法是javac動態(tài)生成的,是這樣嗎?
我們還是通過源碼來確認(rèn)下這個(gè)疑問。
// 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方法里添加了方法體。
怎么樣,現(xiàn)在一切都非常明朗了吧,values方法會拷貝數(shù)組$VALUES的值,然后返回給我們。
希望能對大家有所幫助。
完。
更多原創(chuàng)文章,請關(guān)注我微信公眾號:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/76128.html
摘要:原文你真的會克隆對象嗎開始之前在開始聊克隆之前,我們還是先來看看數(shù)據(jù)類型。值通過函數(shù)生成,是獨(dú)一無二的。同時(shí),中規(guī)定了對象的屬性名有兩種類型,一種是字符串,另一種就是類型。返回一個(gè)數(shù)組,包含對象自身的所有屬性的鍵名。 原文:你真的會克隆對象嗎 開始之前 在開始聊克隆之前,我們還是先來看看js數(shù)據(jù)類型。js的數(shù)據(jù)類型分為基本數(shù)據(jù)類型和復(fù)雜數(shù)據(jù)類型。 基本數(shù)據(jù)類型:Number、Bool...
摘要:它接受任意數(shù)量的源對象,枚舉它們的所有屬性并分配給。所以現(xiàn)在怎么辦有幾種方法可以創(chuàng)建一個(gè)對象的深拷貝。為了防止發(fā)生任何意外,請使用而不是。我想測量哪種方法是最高性能的。圖表以下是,和中不同技術(shù)的性能。 原文:Deep-copying in JavaScript - DasSur.ma 如何在 JavaScript 中拷貝一個(gè)對象?對于這個(gè)很簡單的問題,但是答案卻不簡單。 引用傳值 在...
摘要:介一回,偶們來聊一下用中的類,有些盆友可能用過或者的,知道語法糖,可是在中并沒有,中需要用到構(gòu)造函數(shù)來模擬類。而且要注意一點(diǎn),構(gòu)造函數(shù)沒有語句,是自動返回。 本回內(nèi)容介紹 上一回聊到JS的Function類型,做了柯里化,數(shù)組去重,排序的題。 介一回,偶們來聊一下用JS中的類,有些盆友可能用過ES6或者TypeScript的,知道Class語法糖,可是在ES5中并沒有,ES5中需要用到...
摘要:網(wǎng)站的面試專題學(xué)習(xí)筆記非可變性和對象引用輸出為,前后皆有空格。假定棧空間足夠的話,盡管遞歸調(diào)用比較難以調(diào)試,在語言中實(shí)現(xiàn)遞歸調(diào)用也是完全可行的。棧遵守規(guī)則,因此遞歸調(diào)用方法能夠記住調(diào)用者并且知道此輪執(zhí)行結(jié)束之返回至當(dāng)初的被調(diào)用位置。 ImportNew 網(wǎng)站的Java面試專題學(xué)習(xí)筆記 1. 非可變性和對象引用 String s = Hello ; s += World ; s.tr...
摘要:木易楊注意原始類型被包裝為對象木易楊原始類型會被包裝,和會被忽略。木易楊原因在于時(shí),其屬性描述符為不可寫,即。木易楊解決方法也很簡單,使用我們在進(jìn)階期中介紹的就可以了,使用如下。 引言 上篇文章介紹了賦值、淺拷貝和深拷貝,其中介紹了很多賦值和淺拷貝的相關(guān)知識以及兩者區(qū)別,限于篇幅只介紹了一種常用深拷貝方案。 本篇文章會先介紹淺拷貝 Object.assign 的實(shí)現(xiàn)原理,然后帶你手動實(shí)...
閱讀 3241·2021-11-15 11:37
閱讀 2458·2021-09-29 09:48
閱讀 3821·2021-09-22 15:55
閱讀 3021·2021-09-22 10:02
閱讀 2641·2021-08-25 09:40
閱讀 3236·2021-08-03 14:03
閱讀 1702·2019-08-29 13:11
閱讀 1576·2019-08-29 12:49