日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

理解Java枚举类型

發布時間:2025/4/14 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理解Java枚举类型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?(參考資料:深入理解java enum)

1、原理:對編譯后的class文件javap反編譯可以看出,定義的枚舉類繼承自java.lang.Enum抽象類且通過public static final定義了幾個常量作為枚舉常量。示例:

1 //定義枚舉類型 2 enum Day { 3 MONDAY, TUESDAY, WEDNESDAY, 4 THURSDAY, FRIDAY, SATURDAY, SUNDAY 5 } 6 7 //對應的完整內容 8 //反編譯Day.class 9 final class Day extends Enum 10 { 11 //編譯器為我們添加的靜態的values()方法 12 public static Day[] values() 13 { 14 return (Day[])$VALUES.clone(); 15 } 16 //編譯器為我們添加的靜態的valueOf()方法,注意間接調用了Enum也類的valueOf方法 17 public static Day valueOf(String s) 18 { 19 return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s); 20 } 21 //私有構造函數 22 private Day(String s, int i) 23 { 24 super(s, i); 25 } 26 //前面定義的7種枚舉實例 27 public static final Day MONDAY; 28 public static final Day TUESDAY; 29 public static final Day WEDNESDAY; 30 public static final Day THURSDAY; 31 public static final Day FRIDAY; 32 public static final Day SATURDAY; 33 public static final Day SUNDAY; 34 private static final Day $VALUES[]; 35 36 static 37 { 38 //實例化枚舉實例 39 MONDAY = new Day("MONDAY", 0); 40 TUESDAY = new Day("TUESDAY", 1); 41 WEDNESDAY = new Day("WEDNESDAY", 2); 42 THURSDAY = new Day("THURSDAY", 3); 43 FRIDAY = new Day("FRIDAY", 4); 44 SATURDAY = new Day("SATURDAY", 5); 45 SUNDAY = new Day("SUNDAY", 6); 46 $VALUES = (new Day[] { 47 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY 48 }); 49 } 50 } 枚舉類反編譯后的源碼

java.lang.Enum抽象類定義了一些方法:

返回類型方法名稱方法說明
intcompareTo(E o)比較此枚舉與指定對象的順序
booleanequals(Object other)當指定對象等于此枚舉常量時,返回 true。
Class<?>getDeclaringClass()返回與此枚舉常量的枚舉類型相對應的 Class 對象
Stringname()返回此枚舉常量的名稱,在其枚舉聲明中對其進行聲明
intordinal()返回枚舉常量的序數(它在枚舉聲明中的位置,其中初始常量序數為零)
StringtoString()返回枚舉常量的名稱,它包含在聲明中
static<T extends Enum<T>> Tstatic valueOf(Class<T> enumType, String name)返回帶指定名稱的指定枚舉類型的枚舉常量。

?主要源碼:

public abstract class Enum<E extends Enum<E>>implements Comparable<E>, Serializable {private final String name; //枚舉字符串名稱public final String name() {return name;}private final int ordinal;//枚舉順序值public final int ordinal() {return ordinal;}//枚舉的構造方法,只能由編譯器調用protected Enum(String name, int ordinal) {this.name = name;this.ordinal = ordinal;}public String toString() {return name;}public final boolean equals(Object other) {return this==other;}//比較的是ordinal值public final int compareTo(E o) {Enum<?> other = (Enum<?>)o;Enum<E> self = this;if (self.getClass() != other.getClass() && // optimizationself.getDeclaringClass() != other.getDeclaringClass())throw new ClassCastException();return self.ordinal - other.ordinal;//根據ordinal值比較大小 }@SuppressWarnings("unchecked")public final Class<E> getDeclaringClass() {//獲取class對象引用,getClass()是Object的方法Class<?> clazz = getClass();//獲取父類Class對象引用Class<?> zuper = clazz.getSuperclass();return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;}public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {//enumType.enumConstantDirectory()獲取到的是一個map集合,key值就是name值,value則是枚舉變量值 //enumConstantDirectory是class對象內部的方法,根據class對象獲取一個map集合的值 T result = enumType.enumConstantDirectory().get(name);if (result != null)return result;if (name == null)throw new NullPointerException("Name is null");throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name);}//.....省略其他沒用的方法 } java.lang.Enum

2、可以把枚舉類型當成常規類,即我們可以向枚舉類中添加方法和變量。但是枚舉常量定義必須在方法定義前面,否則編譯報錯。示例:

1 public enum Day2 { 2 MONDAY("星期一"), 3 TUESDAY("星期二"), 4 WEDNESDAY("星期三"), 5 THURSDAY("星期四"), 6 FRIDAY("星期五"), 7 SATURDAY("星期六"), 8 SUNDAY("星期日");//記住要用分號結束 9 10 private String desc;//中文描述 11 12 /** 13 * 私有構造,防止被外部調用 14 * @param desc 15 */ 16 private Day2(String desc){ 17 this.desc=desc; 18 } 19 20 /** 21 * 定義方法,返回描述,跟常規類的定義沒區別 22 * @return 23 */ 24 public String getDesc(){ 25 return desc; 26 } 27 28 public static void main(String[] args){ 29 for (Day2 day:Day2.values()) { 30 System.out.println("name:"+day.name()+ 31 ",desc:"+day.getDesc()); 32 } 33 } 34 35 /** 36 輸出結果: 37 name:MONDAY,desc:星期一 38 name:TUESDAY,desc:星期二 39 name:WEDNESDAY,desc:星期三 40 name:THURSDAY,desc:星期四 41 name:FRIDAY,desc:星期五 42 name:SATURDAY,desc:星期六 43 name:SUNDAY,desc:星期日 44 */ 45 } 枚舉類型自定義方法 public enum EnumDemo3 {FIRST{@Overridepublic String getInfo() {return "FIRST TIME";}},SECOND{@Overridepublic String getInfo() {return "SECOND TIME";}};/*** 定義抽象方法* @return*/public abstract String getInfo();//測試public static void main(String[] args){System.out.println("F:"+EnumDemo3.FIRST.getInfo());System.out.println("S:"+EnumDemo3.SECOND.getInfo());/**輸出結果:F:FIRST TIMES:SECOND TIME*/} } 枚舉類型中定義抽象方法

3、定義的枚舉類型無法被繼承(看反編譯后的源碼可知類被final修飾了)也無法繼承其他類(因其已默認繼承了Enum類,而Java只允許單繼承),但可以實現接口。一個很好的示例:

public enum Meal{APPETIZER(Food.Appetizer.class),MAINCOURSE(Food.MainCourse.class),DESSERT(Food.Dessert.class),COFFEE(Food.Coffee.class);private Food[] values;private Meal(Class<? extends Food> kind) {//通過class對象獲取枚舉實例values = kind.getEnumConstants();}public interface Food {enum Appetizer implements Food {SALAD, SOUP, SPRING_ROLLS;}enum MainCourse implements Food {LASAGNE, BURRITO, PAD_THAI,LENTILS, HUMMOUS, VINDALOO;}enum Dessert implements Food {TIRAMISU, GELATO, BLACK_FOREST_CAKE,FRUIT, CREME_CARAMEL;}enum Coffee implements Food {BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,LATTE, CAPPUCCINO, TEA, HERB_TEA;}} } 枚舉類實現接口

?4、枚舉與單例:使用枚舉單例的寫法,我們完全不用考慮序列化和反射的問題。枚舉序列化是由jvm保證的,每一個枚舉類型和定義的枚舉變量在JVM中都是唯一的,在枚舉類型的序列化和反序列化上,Java做了特殊的規定:在序列化時Java僅僅是將枚舉對象的name屬性輸出到結果中,反序列化的時候則是通過java.lang.Enum的valueOf方法來根據名字查找枚舉對象。同時,編譯器是不允許任何對這種序列化機制的定制的并禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法,從而保證了枚舉實例的唯一性(也說明了只有Java中只有編譯器能創建枚舉實例)。

如何確保反序列化時不會破壞單例:根據valueOf(name)得到反序列化后對象,valueOf根據枚舉常量名獲取對應枚舉常量

public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {T result = enumType.enumConstantDirectory().get(name);if (result != null)return result;if (name == null)throw new NullPointerException("Name is null");throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name);}Map<String, T> enumConstantDirectory() {if (enumConstantDirectory == null) {//getEnumConstantsShared最終通過反射調用枚舉類的values方法T[] universe = getEnumConstantsShared();if (universe == null)throw new IllegalArgumentException(getName() + " is not an enum type");Map<String, T> m = new HashMap<>(2 * universe.length);//map存放了當前enum類的所有枚舉實例變量,以name為key值for (T constant : universe)m.put(((Enum<?>)constant).name(), constant);enumConstantDirectory = m;}return enumConstantDirectory;}private volatile transient Map<String, T> enumConstantDirectory = null; valueOf

如何確保反射不會破壞單例:反射源碼里對于枚舉類型反射直接拋異常所以反射生成不了枚舉類型實例

public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {//獲取枚舉類的構造函數(前面的源碼已分析過)Constructor<SingletonEnum> constructor=SingletonEnum.class.getDeclaredConstructor(String.class,int.class);constructor.setAccessible(true);//創建枚舉SingletonEnum singleton=constructor.newInstance("otherInstance",9);}//運行結果 Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objectsat java.lang.reflect.Constructor.newInstance(Constructor.java:417)at zejian.SingletonEnum.main(SingletonEnum.java:38)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)//newInstance源碼public T newInstance(Object ... initargs)throws InstantiationException, IllegalAccessException,IllegalArgumentException, InvocationTargetException{if (!override) {if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {Class<?> caller = Reflection.getCallerClass();checkAccess(caller, clazz, null, modifiers);}}//這里判斷Modifier.ENUM是不是枚舉修飾符,如果是就拋異常if ((clazz.getModifiers() & Modifier.ENUM) != 0)throw new IllegalArgumentException("Cannot reflectively create enum objects");ConstructorAccessor ca = constructorAccessor; // read volatileif (ca == null) {ca = acquireConstructorAccessor();}@SuppressWarnings("unchecked")T inst = (T) ca.newInstance(initargs);return inst;} View Code

在單例中,枚舉也不是萬能的。在android開發中,內存優化是個大塊頭,而使用枚舉時占用的內存常常是靜態變量的兩倍還多,因此android官方在內存優化方面給出的建議是盡量避免在android中使用enum。

5、EnumMap與EnumSet:見上述參考資料。

前者與HashMap類似,只不過key是Enum類型且不能為null。

后者則采用位向量實現,對于枚舉值個數少于64的用一個long來標記(RegularEnumSet)否則用long[ ]來標記(JumboEnumSet)。

?

轉載于:https://www.cnblogs.com/z-sm/p/9299792.html

總結

以上是生活随笔為你收集整理的理解Java枚举类型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 姑娘第5集在线观看免费 | 亚洲AV无码片久久精品 | 美女三级黄色 | 久久精品欧美一区二区三区不卡 | 老妇女av| 国产激情一区二区三区在线观看 | 99色这里只有精品 | 成年人网站在线观看视频 | 国产乱妇4p交换乱免费视频 | 极品美女开粉嫩精品 | 欧美日韩视频免费观看 | 成人毛片18女人毛片 | 爆乳熟妇一区二区三区 | 日韩免费高清视频 | 国产 日韩 欧美在线 | 国产无码精品一区二区 | 日本不卡在线播放 | 日韩电影一区二区三区 | 黄色小视频免费观看 | 日韩最新网址 | 国产xxxxx视频 | 一区二区三区播放 | 一级全黄裸体片 | 欧洲熟妇的性久久久久久 | 亚洲精品在线免费 | 成人在线观看www | 性欧美熟妇videofreesex | 成人免费淫片aa视频免费 | 无码人妻一区二区三区线 | 四虎影视免费 | 91黄色免费网站 | 夜夜嗨av色一区二区不卡 | 午夜久久影院 | 看免费黄色大片 | 亚洲欧美日韩国产成人精品影院 | 粉嫩在线 | 欧美专区亚洲专区 | 亚洲天堂色| 国产凹凸一区二二区 | 国产免费av一区二区三区 | 茄子av| 黄床大片 | 草比网站 | 亚洲成a人片777777久久 | 精品国产va久久久久久久 | 人妻丝袜一区 | 久久亚洲高清 | 91中文字幕在线播放 | www.一级片| 女生扒开尿口 | 欧美爱爱网 | 波多野结衣 在线 | 男人日女人网站 | 亚洲精品久久久久久久久久久 | 伊人色影院 | 日本午夜电影 | 日本一区二区三区免费在线观看 | 亚洲乱熟女一区二区三区小说 | 黑人操亚洲人 | 九九视频这里只有精品 | 色婷婷久久一区二区三区麻豆 | 国产在线操 | 天天添天天射 | 日日cao | 黄色国产在线观看 | 亚洲精品乱码久久久久久按摩观 | 国产在线观看 | 影音先锋亚洲资源 | 一级黄色免费看 | 99久久免费精品 | 久久婷婷国产麻豆91 | 日本精品视频一区二区三区 | 欧美日韩黄色大片 | 国产熟女高潮一区二区三区 | 三上悠亚激情av一区二区三区 | 高清18麻豆 | 国产三级短视频 | 一起操在线 | 日韩激情片| 日本一区二区三区免费观看 | 狠狠v欧美v日韩v亚洲ⅴ | 少妇被按摩师摸高潮了 | 亚洲国产日韩在线一区 | 看了下面会湿的视频 | 日韩天堂在线视频 | 成人图片小说 | 蜜乳av 懂色av 粉嫩av | 精品国产乱码久久久人妻 | 国产又粗又猛又爽又黄的视频在线观看动漫 | 看免费的毛片 | 亚洲av久久久噜噜噜熟女软件 | 免费a v视频 | 91麻豆映画传媒 | 青草草在线观看 | 成人一级黄色 | av在线播放国产 | 亚洲人在线 | 日本黄网站在线观看 | 久久久久久久国产精品 |