国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁 > 學院 > 開發設計 > 正文

關于Java中枚舉Enum的深入剖析

2019-11-14 08:45:14
字體:
來源:轉載
供稿:網友

學習java的同學注意了!!! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:183993990  我們一起學Java!

在編程語言中我們,都會接觸到枚舉類型,通常我們進行有窮的列舉來實現一些限定。Java也不例外。Java中的枚舉類型為Enum,本文將對枚舉進行一些比較深入的剖析。

什么是Enum

Enum是自Java 5 引入的特性,用來方便Java開發者實現枚舉應用。一個簡單的Enum使用如下。

// ColorEnum.javapublic enum ColorEmun {    RED,    GREEN,    YELLOW}public void setColorEnum(ColorEmun colorEnum) {    //some code here}setColorEnum(ColorEmun.GREEN);

為什么會有Enum

在Enum之前的我們使用類似如下的代碼實現枚舉的功能.

public static final int COLOR_RED = 0;public static final int COLOR_GREEN = 1;public static final int COLOR_YELLOW = 2;public void setColor(int color) {    //some code here}//調用setColor(COLOR_RED)

然而上面的還是有不盡完美的地方

setColor(COLOR_RED)與setColor(0)效果一樣,而后者可讀性很差,但卻可以正常運行setColor方法可以接受枚舉之外的值,比如setColor(3),這種情況下程序可能出問題

概括而言,傳統枚舉有如下兩個弊端

安全性可讀性,尤其是打印日志時

因此Java引入了Enum,使用Enum,我們實現上面的枚舉就很簡單了,而且還可以輕松避免傳入非法值的風險.

枚舉原理是什么

Java中Enum的本質其實是在編譯時期轉換成對應的類的形式。

首先,為了探究枚舉的原理,我們先簡單定義一個枚舉類,這里以季節為例,類名為Season,包含春夏秋冬四個枚舉條目.

public enum Season {    SPRING,    SUMMER,    AUTUMN,    WINTER}

然后我們使用javac編譯上面的類,得到class文件.

javac Season.java

然后,我們利用反編譯的方法來看看字節碼文件究竟是什么.這里使用的工具是javap的簡單命令,先列舉一下這個Season下的全部元素.

company javap SeasonWarning: Binary file Season contains com.company.SeasonCompiled from "Season.java"public final class com.company.Season extends java.lang.Enum<com.company.Season> {  public static final com.company.Season SPRING;  public static final com.company.Season SUMMER;  public static final com.company.Season AUTUMN;  public static final com.company.Season WINTER;  public static com.company.Season[] values();  public static com.company.Season valueOf(java.lang.String);  static {};}

從上反編譯結果可知

java代碼中的Season轉換成了繼承自的java.lang.enum的類既然隱式繼承自java.lang.enum,也就意味java代碼中,Season不能再繼承其他的類Season被標記成了final,意味著它不能被繼承

static代碼塊

使用javap具體反編譯class文件,得到靜態代碼塊相關的結果為

static {};    Code:       0: new           #4                  // class com/company/Season       3: dup       4: ldc           #7                  // String SPRING       6: iconst_0       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V      10: putstatic     #9                  // Field SPRING:Lcom/company/Season;      13: new           #4                  // class com/company/Season      16: dup      17: ldc           #10                 // String SUMMER      19: iconst_1      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V      23: putstatic     #11                 // Field SUMMER:Lcom/company/Season;      26: new           #4                  // class com/company/Season      29: dup      30: ldc           #12                 // String AUTUMN      32: iconst_2      33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V      36: putstatic     #13                 // Field AUTUMN:Lcom/company/Season;      39: new           #4                  // class com/company/Season      42: dup      43: ldc           #14                 // String WINTER      45: iconst_3      46: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V      49: putstatic     #15                 // Field WINTER:Lcom/company/Season;      52: iconst_4      53: anewarray     #4                  // class com/company/Season      56: dup      57: iconst_0      58: getstatic     #9                  // Field SPRING:Lcom/company/Season;      61: aastore      62: dup      63: iconst_1      64: getstatic     #11                 // Field SUMMER:Lcom/company/Season;      67: aastore      68: dup      69: iconst_2      70: getstatic     #13                 // Field AUTUMN:Lcom/company/Season;      73: aastore      74: dup      75: iconst_3      76: getstatic     #15                 // Field WINTER:Lcom/company/Season;      79: aastore      80: putstatic     #1                  // Field $VALUES:[Lcom/company/Season;      83: return}

其中

0~52為實例化SPRING, SUMMER, AUTUMN, WINTER53~83為創建Season[]數組$VALUES,并將上面的四個對象放入數組的操作.

values方法

values方法的的返回值實際上就是上面$VALUES數組對象

swtich中的枚舉

在Java中,switch-case是我們經常使用的流程控制語句.當枚舉出來之后,switch-case也很好的進行了支持.

比如下面的代碼是完全正常編譯,正常運行的.

public static void main(String[] args) {        Season season = Season.SPRING;        switch(season) {            case SPRING:                System.out.println("It's Spring");                break;            case WINTER:                System.out.println("It's Winter");                break;            case SUMMER:                System.out.println("It's Summer");                break;            case AUTUMN:                System.out.println("It's Autumn");                break;        }    }

不過,通常情況下switch-case支持類似int的類型,那么它是怎么做到對Enum的支持呢,我們反編譯上述方法看一下字節碼的真實情況.

public static void main(java.lang.String[]);    Code:       0: getstatic     #2                  // Field com/company/Season.SPRING:Lcom/company/Season;       3: astore_1       4: getstatic     #3                  // Field com/company/Main$1.$SwitchMap$com$company$Season:[I       7: aload_1       8: invokevirtual #4                  // Method com/company/Season.ordinal:()I      11: iaload      12: tableswitch   { // 1 to 4                     1: 44                     2: 55                     3: 66                     4: 77               default: 85          }      44: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;      47: ldc           #6                  // String It's Spring      49: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V      52: goto          85      55: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;      58: ldc           #8                  // String It's Winter      60: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V      63: goto          85      66: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;      69: ldc           #9                  // String It's Summer      71: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V      74: goto          85      77: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;      80: ldc           #10                 // String It's Autumn      82: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V      88: return

注意上面代碼塊有這樣的一段代碼

8: invokevirtual #4                  // Method com/company/Season.ordinal:()I

事實果真如此,在switch-case中,還是將Enum轉成了int值(通過調用Enum.oridinal()方法)

枚舉與混淆

在Android開發中,進行混淆是我們在發布前必不可少的工作,混下后,我們能增強反編譯的難度,在一定程度上保護了增強了安全性.

而開發人員處理混淆更多的是將某些元素加入不混淆的名單,這里枚舉就是需要排除混淆的.

在默認的混淆配置文件中,已經加入了關于對枚舉混淆的處理

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations-keepclassmembers enum * {    public static **[] values();    public static ** valueOf(java.lang.String);}

關于為什么要保留values()方法和valueOf()方法,請參考文章讀懂 Android 中的代碼混淆 關于枚舉的部分

使用proguard優化

使用Proguard進行優化,可以將枚舉盡可能的轉換成int。配置如下

-optimizations class/unboxing/enum

確保上述代碼生效,需要確proguard配置文件不包含-dontoptimize指令。

當我們使用gradlew打包是,看到類似下面的輸出,即Number of unboxed enum classes:1代表已經將一個枚舉轉換成了int的形式。

Optimizing...  Number of finalized classes:                 0   (disabled)  Number of unboxed enum classes:              1  Number of vertically merged classes:         0   (disabled)  Number of horizontally merged classes:       0   (disabled)

枚舉單例

單例模式是我們在日常開發中可謂是最常用的設計模式.

然后要設計好單例模式,無非考慮一下幾點

確保只有唯一實例,不多創建多余實例確保實例按需創建.

因此傳統的做法想要實現單例,大致有一下幾種

餓漢式加載懶漢式synchronize和雙重檢查利用java的靜態加載機制

相比上述的方法,使用枚舉也可以實現單例,而且還更加簡單.

public enum AppManager {    INSTANCE;    private String tagName;    public void setTag(String tagName) {        this.tagName = tagName;    }    public String getTag() {        return tagName;    }}

調用起來也更加簡單

AppManager.INSTANCE.getTag();

枚舉如何確保唯一實例

因為獲得實例只能通過AppManager.INSTANCE

下面的方式是不可以的

AppManager appManager = new AppManager(); //compile error

關于單例模式,可以閱讀單例這種設計模式了解更多。

(Android中)該不該用枚舉

既然上面提到了枚舉會轉換成類,這樣理論上造成了下面的問題

增加了dex包的大小,理論上dex包越大,加載速度越慢同時使用枚舉,運行時的內存占用也會相對變大

關于上面兩點的驗證,秋百萬已經做了詳細的論證,大家可以參考這篇文章《Android 中的 Enum 到底占多少內存?該如何用?》

關于枚舉是否使用的結論,大家可以參考

如果你開發的是Framework不建議使用enum如果是簡單的enum,可以使用int很輕松代替,則不建議使用enum另外,如果是Android中,可以使用下面介紹的枚舉注解來實現。除此之外,我們還需要對比可讀性和易維護性來與性能進行衡量,從中進行做出折中

在Android中的替代

Android中新引入的替代枚舉的注解有IntDef和StringDef,這里以IntDef做例子說明一下.

public class Colors {    @IntDef({RED, GREEN, YELLOW})    @Retention(RetentionPolicy.SOURCE)    public @interface LightColors{}    public static final int RED = 0;    public static final int GREEN = 1;    public static final int YELLOW = 2;}聲明必要的int常量聲明一個注解為LightColors使用@IntDef修飾LightColors,參數設置為待枚舉的集合使用@Retention(RetentionPolicy.SOURCE)指定注解僅存在與源碼中,不加入到class文件中

比如我們用來標注方法的參數

private void setColor(@Colors.LightColors int color) {        Log.d("MainActivity", "setColor color=" + color);}

調用的該方法的時候

setColor(Colors.GREEN);

以上就是我對Java中enum的一些深入的剖析,歡迎大家不吝賜教。

學習Java的同學注意了!!! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:183993990  我們一起學Java!


上一篇:centos 安裝 eclipse

下一篇:lucene總結

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
不卡av免费观看| 毛片网站在线观看| 午夜伦全在线观看| 天堂在线一二区| 国产日韩网站| 亚洲精品乱码电影在线观看| 在线看黄网站| 日本电影在线观看| av在线免费播放网站| 久久久久久久美女| 中文字幕网在线| 尤物在线视频观看| 狠狠干五月天| www.香蕉视频在线观看| 天堂资源中文在线| 91涩漫在线观看c| 免费a级在线播放| 国产精品入口麻豆高清| jizz性欧美| 国产91在线视频蝌蚪| 九九热视频在线| 影音先锋中文字幕在线 | 99视频免费在线观看| 91看片在线观看| 国产理论片免费观看| 精品麻豆一区二区三区| 国产中文伊人| 日本18视频网站| 国产xxx在线| 国产精品入口麻豆完整版| 免费在线看v| 亚洲а∨精品天堂在线| 国产激情网址| 国产精品美女一区二区视频| 开心丁香婷婷深爱五月| 97在线免费| 国产网站免费观看| 精品资源在线看| 国产女人在线视频| 高清欧美精品xxxxx在线看| av在线二区| 亚洲www色| 亚洲91av| 久久99精品久久久久久野外| 狂野欧美性猛交xxxx乱大交| 免费的黄网站在线观看| 久热免费在线视频| 国产中文字幕第一页| 国产女人伦码一区二区三区不卡| 轻轻色免费在线视频| 免费a在线看| 青青草在线视频免费观看| 思思99精品视频在线观看| 白浆爆出在线观看| 免费a级在线播放| 国产在线麻豆精品| 国产激情在线观看| 永久免费在线观看| 欧美精品日韩少妇| 国产一级激情| av网站大全在线| 1区2区3区在线| 一色桃子av在线| 最新av免费看| 天海翼中文字幕| 国产视频资源| 免费电影网站在线视频观看福利| www.av在线视频| 最近中文字幕mv免费高清在线| 精品无人区乱码1区2区3区免费| 在线成人综合色一区| 国产乱子视频| 四虎成人欧美精品在永久在线| 日本中文字幕高清视频| a√在线视频| 国产精品亚洲色图| www久久日com| 伊人网在线视频| 国产网站麻豆精品视频| 久久99精品久久久久久野外| 国产福利电影在线| 国产小视频在线| 日本动漫理论片在线观看网站| 国产三级在线免费| 激情亚洲综合网| 日韩精品免费一区二区| 国产呻吟对白刺激无套视频在线| 欧美另类在线视频| av中文在线| 夜夜嗨yeyeh| 91九色在线看| 精品久久亚洲一级α| 国产高清大尺度一区二区不卡| 国产麻豆精品视频一区二区| 碰草在线视频| 日本久久网站| 超碰免费在线观看| 99爱视频在线观看| 在线中文字幕视频| 永久免费在线观看| 999在线视频| 在线国产一区二区三区| 国产不卡视频| 在线黄色国产电影| 亚洲欧美一区二区三区在线播放| 精品欧美不卡一区二区在线观看| 中文字幕在线播放网址| 国产一二三区精品视频| 国产精品冒白浆免费视频| 国产成人久久精品77777| 精品无人区乱码1区2区3区免费| 91激情在线| 精品日韩av| 免费看的毛片| 国产一级视频| 亚洲尤物在线视频| 久久精品无码一区二区日韩av| 青青九九免费视频在线| 久久精品国产亚洲a∨麻豆| 成人精品福利| 国产95在线|亚洲| 欧美韩日国产| 国产精品久久久精品a级小说| 91青青在线视频| 女同一区二区免费aⅴ| 中文字幕在线观看av| 在线黄色.com| 九九精品视频在线观看九九| 国产一卡二卡3卡4卡四卡在线| 国产精品第八页| 青青久在线视频免费观看| 国产三级自拍| 免费在线超碰| 精品一区二区三区在线观看l| 欧美艹逼视频| 精品一区二区三区高清免费不卡| 青草在线视频在线观看| 国产三区视频在线观看| 久热中文字幕精品视频在线| 精品国产高清a毛片无毒不卡 | av在线电影观看| 国产九色视频| 日本不卡视频一区二区| 精品美女视频在线观看免费软件| 国产乱视频在线观看| 亚洲人在线播放| 国产黄色免费| 91av资源在线| 久久久久国产精品嫩草影院| 亚洲欧美久久婷婷爱综合一区天堂| 国产区视频在线播放| 国产精品一区二区三区四区色| www.三级.com| а√天堂8资源在线官网 | 在线国产1区| 国产成人无吗| 国产欧美日本亚洲精品一4区| 超碰国产在线| 麻豆精品永久免费视频| 欧美日韩在线视频免费观看| a视频在线播放| www.亚洲视频| 欧美日韩综合高清一区二区| 亚洲欧美久久婷婷爱综合一区天堂| 91资源在线观看| 中文乱码字幕高清在线观看| 国产毛片在线看| 国产美女视频一区二区三区| 天天操天天操天天色天天要| 国产麻豆一级片| 国产黄色大片在线观看| 在线中文av| 超碰免费97在线观看| 天堂资源最新版在线视频观看免费网| 国产有码在线| 国产精品美女一区二区三区四区 | 中文字幕在线观看av| 午夜视频99| 国产二级c片l毛片| 亚洲人av在线| 中文字幕在线影院| 国产精美视频| 五月综合激情在线| 中文字幕欧美日韩在线不卡| √天堂资源中文www| 亚洲91av| 天堂在线免费观看| 97一区二区三区| 欧美日韩国产亚洲沙发| 国产一区二区三区福利| 在线免费观看你懂的| 美女被人操视频在线观看| 国产系列在线观看| 亚洲wwwwww| 国产农村一级特黄α**毛片 | 国产黄色片中文字幕| 亚洲精品少妇久久久久久| 国产免费麻豆视频| 伊人狠狠av| 国产丝袜视频在线播放|