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的三个值的区分自己百度一下,这里不做解释
  • 替换的局限性

这样,我们在调用接口的时候,如果传入非法的数值,就会在编译阶段报错提醒,避免了参数错误引起的问题。

 

结论:所以没有谁替换谁,都是结合业务需求自己选择

 

如果对您有帮助,欢迎扫码关注:

                                                                                      

 

 

 

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