今天是520,簡單記錄一下枚舉的使用和替換(貌似沒有任何關係哈......);文章的主要內容包括以下幾個部分
- 學習和記錄的原因
- 靜態常量標識的使用
- 枚舉替換靜態常量以及擴展
- 使用註解替換枚舉
好了,下面就來逐一講述一下。
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的三個值的區分自己百度一下,這裏不做解釋
- 替換的侷限性
這樣,我們在調用接口的時候,如果傳入非法的數值,就會在編譯階段報錯提醒,避免了參數錯誤引起的問題。
結論:所以沒有誰替換誰,都是結合業務需求自己選擇
如果對您有幫助,歡迎掃碼關注: