Android中使用枚舉的來來去去

        今天是520,簡單記錄一下枚舉的使用和替換(貌似沒有任何關係哈......);文章的主要內容包括以下幾個部分

  1. 學習和記錄的原因
  2. 靜態常量標識的使用
  3. 枚舉替換靜態常量以及擴展
  4. 使用註解替換枚舉

好了,下面就來逐一講述一下。

1, 學習和記錄的原因

          靜態在看Android Developers網站,在看到性能優化中縮減APK體積大小的時候,裏面說到:

避免使用枚舉

單個枚舉會使應用的 classes.dex 文件增加大約 1.0 到 1.4KB 的大小。這些增加的大小會快速累積,產生複雜的系統或共享庫。如果可能,請考慮使用 @IntDef 註釋和代碼縮減移除枚舉並將它們轉換爲整數。此類型轉換可保留枚舉的各種安全優勢。

ok,這裏就是觸發我記錄本片博客的原因。 

 

2,靜態常量標識的使用

考慮一種場景,我們列好了一個健身計劃,以一週爲週期,比如,週一舉重,週二瑜伽,週三睡覺等等;
我們在設計接口的時候,自然會根據傳入的是周幾來執行具體的計劃,於是就有了以下的代碼(考慮到接口的擴展性,我把其設計爲泛型接口)

public interface IPlan<T> {
	void exercise(T t);
}

ok,接口有了之後,我們就來考慮實現了,我們定義一個實現了XiaoMing,代碼如下:

public class XiaoMing implements IPlan<Integer> {

	@Override
	public void exercise(Integer i) {
		// TODO 根據傳入的i(周幾)來判斷執行什麼訓練
		switch (i) {
		case DayTag.MONDAY:
			System.out.println("週一我練習舉重");
			break;
		case DayTag.TUESDAY:
			System.out.println("週二我練習瑜伽");
			break;
		case DayTag.WEDNESDAY:
			System.out.println("週三我練習跑步");
			break;
		case DayTag.THURSDAY:
			System.out.println("週四我練習游泳");
			break;
		case DayTag.FRIDAY:
			System.out.println("週五我練習籃球");
			break;
		case DayTag.SATURDAY:
			System.out.println("週六我練習羽毛球");
			break;
		case DayTag.SUNDAY:
			System.out.println("週日我睡覺");
			break;
		default:
			System.out.println("數據異常");
			break;
		}

	}
}

其中的DayTag就是我們的鏡頭靜常量數據池,代碼如下:

public class DayTag {
	public static final int MONDAY=1;
	public static final int TUESDAY=2;
	public static final int WEDNESDAY=3;
	public static final int THURSDAY=4;
	public static final int FRIDAY=5;
	public static final int SATURDAY=6;
	public static final int SUNDAY=7;
}

可見,我們就是通過靜態不可變常量int值1-7來標識週一到週日,這樣做,簡單明瞭,沒有任何不理解的地方可言,好了,下面就來看看具體的接口調用:

		XiaoMing xm=new XiaoMing();
		for(int i=1;i<9;i++) {
			xm.exercise(i);
		}

運行結果如下:

哎,怎麼會有異常數據了,原來是因爲我們沒有對輸入數據做限制,好吧,既然問題產生了,我們該如何解決了,下面就要用到我們的枚舉了。

3,枚舉替換靜態常量以及擴展

上一步中,我們遇到了使用靜態常量來標識的時候出現了數據校驗問題,這部分我們就來用枚舉來解決這一問題。首先關於枚舉的概念大家可以百度一下,很多介紹,我這裏就放一下廖雪峯老師網站的鏈接,不理解的可以先看一下。

回到我們的主題上來,首先先根據需要創建枚舉類,代碼如下:

enum DayEnum {
	MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

沒有任何花裏胡哨的東西,關鍵字一懟加上你要定義的枚舉常量就OK了,下面就來看看今天的使用,這次我們換XiaoZhang來鍛鍊了。

public class XiaoZhang implements IPlan<DayEnum> {

	@Override
	public void exercise(DayEnum i) {
		// TODO 根據傳入的i(周幾)來判斷執行什麼訓練
		switch (i) {
		case MONDAY:
			System.out.println("週一我練習舉重");
			break;
		case TUESDAY:
			System.out.println("週二我練習瑜伽");
			break;
		case WEDNESDAY:
			System.out.println("週三我練習跑步");
			break;
		case THURSDAY:
			System.out.println("週四我練習游泳");
			break;
		case FRIDAY:
			System.out.println("週五我練習籃球");
			break;
		case SATURDAY:
			System.out.println("週六我練習羽毛球");
			break;
		case SUNDAY:
			System.out.println("週日我睡覺");
			break;
		default:
			System.out.println("數據異常");
			break;
		}
	}

}

代碼調用如下:

//小張
		XiaoZhang xz=new XiaoZhang();
		xz.exercise(DayEnum.MONDAY);

因爲類型做了限定,所以傳入的參數只能是枚舉裏面的幾個常量,其實關於枚舉和靜態常量對比的優點除了數據限定,還有一個就是綁定其他數據

考慮一種相對複雜的場景,我們不僅要讀取傳入的周幾,還有看到當天的鍛鍊時長和飲食計劃,如果使用常量的話,那麼可能就需要幾組數據並且在代碼中進行關聯,甚是麻煩。

3.1 枚舉使用擴展

這次鍛鍊的是XiaoBaWang,首先還是看枚舉的實現:

enum DayEnumPlus {
	
	MONDAY(2.0f,"雞肉",1), TUESDAY(3.0f,"牛肉",2),
	WEDNESDAY(2.0f,"魚肉",3), THURSDAY(2.0f,"鴨肉",4), FRIDAY(2.0f,"豬肉",5),
	SATURDAY(4.0f,"龍蝦",6), SUNDAY(0.0f,"不吃飯",7);
	
	private float mHours;
	private String mFood;
	private int mWeekDay;
	
	private DayEnumPlus(float f,String food,int weekDay) {
		mHours=f;
		mFood=food;
		mWeekDay=weekDay;
	}

	public float getmHours() {
		return mHours;
	}


	public String getmFood() {
		return mFood;
	}


	public int getmWeekDay() {
		return mWeekDay;
	}

	
}

這個枚舉類要複雜一點了,但是沒有什麼,注意一下幾點就行了:

  • 構造私有
  • 枚舉常量定義在類的首行
  • 添加GETTER獲取常量對象屬性值

XiaoBaWang的實現如下:

public class XiaoBaWang implements IPlan<DayEnumPlus> {

	@Override
	public void exercise(DayEnumPlus t) {	
		
		switch(t) {
		
		}
		System.out.println("今天周"+t.getmWeekDay());
		System.out.println("我要鍛鍊"+t.getmHours()+"小時");
		System.out.println("我要吃"+t.getmFood());
	}

}

調用端的就不寫了,沒有什麼特別的。下面就是最後一部分內容了,就是使用註解來替換枚舉了。

 

4,使用註解替換枚舉

這裏的替換應該來說是部分場景替換,也就是上面的非擴展場景的使用替換。我們知道,在使用枚舉的時候,每一個枚舉常量都會產生一個對象,所以就有了:

避免使用枚舉

單個枚舉會使應用的 classes.dex 文件增加大約 1.0 到 1.4KB 的大小。這些增加的大小會快速累積,產生複雜的系統或共享庫。如果可能,請考慮使用 @IntDef 註釋和代碼縮減移除枚舉並將它們轉換爲整數。此類型轉換可保留枚舉的各種安全優勢。

下面就來看看如何使用註解替換枚舉的。具體的實施步驟包括:

  • 自定義註解
  • 使用自定義註解限定接口參數

很簡單,就是上面兩步,下面就來看一下具體編碼,還是以上面爲例,首先自定義註解

  @IntDef({DayTag.MONDAY, DayTag.TUESDAY,DayTag.THURSDAY,
            DayTag.WEDNESDAY,DayTag.FRIDAY,DayTag.SATURDAY,DayTag.SUNDAY,})
    @Retention(RetentionPolicy.SOURCE)
    public @interface DayAnnotation{

    }

這次,輪到XiaoJiLing(自定義註解在實現類內部)來鍛鍊了:

public class XiaoJiLing implements IPlan<Integer> {

            @IntDef({DayTag.MONDAY, DayTag.TUESDAY, DayTag.THURSDAY,
                    DayTag.WEDNESDAY, DayTag.FRIDAY, DayTag.SATURDAY, DayTag.SUNDAY,})
            @Retention(RetentionPolicy.SOURCE)
            public @interface DayAnnotation {

            }

            @Override
            public void exercise(@DayAnnotation Integer t) {
                // TODO Auto-generated method stub
                switch (t) {
                    case DayTag.MONDAY:
                        System.out.println("週一我練習舉重");
                        break;
                    case DayTag.TUESDAY:
                        System.out.println("週二我練習瑜伽");
                        break;
                    case DayTag.WEDNESDAY:
                        System.out.println("週三我練習跑步");
                        break;
                    case DayTag.THURSDAY:
                        System.out.println("週四我練習游泳");
                        break;
                    case DayTag.FRIDAY:
                        System.out.println("週五我練習籃球");
                        break;
                    case DayTag.SATURDAY:
                        System.out.println("週六我練習羽毛球");
                        break;
                    case DayTag.SUNDAY:
                        System.out.println("週日我睡覺");
                        break;
                    default:
                        System.out.println("數據異常");
                        break;
                }
    }
}

這樣我們就避免了因使用枚舉創建對象帶來的文件變大的影響,這裏有幾點注意一下:

  • 註解RetentionPolicy的三個值的區分自己百度一下,這裏不做解釋
  • 替換的侷限性

這樣,我們在調用接口的時候,如果傳入非法的數值,就會在編譯階段報錯提醒,避免了參數錯誤引起的問題。

 

結論:所以沒有誰替換誰,都是結合業務需求自己選擇

 

如果對您有幫助,歡迎掃碼關注:

                                                                                      

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章