今天是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的三个值的区分自己百度一下,这里不做解释
- 替换的局限性
这样,我们在调用接口的时候,如果传入非法的数值,就会在编译阶段报错提醒,避免了参数错误引起的问题。
结论:所以没有谁替换谁,都是结合业务需求自己选择
如果对您有帮助,欢迎扫码关注: