枚举 android 设备,[Android]使用Typedef注解代替枚举

#[Android]使用 Typedef 注解代替枚举

假设我们现在需要通过代码实现这个功能:

1. 定义 1 个变量 x

2. 定义几个常量,将其中一个常量的值赋给 x

3. 根据 x 的值来执行不同的方法

那么我们可以这样做:

~~~

public class Main{

//这里定义一些关于“星期几”的常量

public static final int SUNDAY = 0;

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;

//这个就是我们的变量 x

private int x ;

public int getX() { return x; }

public void setX(int x){ this.x = x; }

//main 方法

public static void main(String[] args){

Main obj = new Main();

//通过set方法来为 x 赋值,

obj.setX(SUNDAY);

int today = obj.getX();

//根据不同的 x 的值,来输出不同的内容

switch(today){

case SUNDAY:

System.out.println("Today is Sunday");

break;

case MONDAY:

System.out.println("Today is Monday");

break;

case TUESDAY:

System.out.println("Today is Tuesday");

break;

case WEDNESDAY:

System.out.println("Today is Wednesday");

break;

case THURSDAY:

System.out.println("Today is Thursday");

break;

case FRIDAY:

System.out.println("Today is Friday");

break;

case SATURDAY:

System.out.println("Today is Saturday");

break;

default:

break;

}

}

}

---------------------

run result:

Today is Sunday

~~~

编译器没有警告,程序运行后,因为我们传入的是 `SUNDAY` ,所以这里输出了 "Today is Sunday" ,我们成功实现了要求的功能,任务完成了。但是仔细看过以后,代码仍然存在问题:`obj.setX(SUNDAY)` 中传入的值可以是任何值,假设我们这样写 `obj.set(100)`,编译器可以正常编译,但是在 `switch` 语句中就不会执行任何 `case` 了。为了限定传入的值,Java 为我们提供了解决这一问题的方法:**Enum** ,就是**枚举**。

让我们使用枚举来重写原来的代码:

~~~

public class Main{

//定义枚举类

public enum WeekDays{

SUNDAY , MONDAY , TUESDAY , WEDNESDAY , THURSDAY , FRIDAY , SATURDAY

}

//定义我们的 x ,这里的 x 的类型已经从 int 变为了 WeekDays

private WeekDays x ;

public WeekDays getX() { return x; }

public void setX(WeekDays x){ this.x = x; }

//main 方法

public static void main(String[] args){

Main obj = new Main();

obj.setX(WeekDays.SUNDAY);

WeekDays today = obj.getX();

//同样使用 switch 来控制输出不同的语句

switch(today){

case SUNDAY:

System.out.println("Today is Sunday");

break;

case MONDAY:

System.out.println("Today is Monday");

break;

case TUESDAY:

System.out.println("Today is Tuesday");

break;

case WEDNESDAY:

System.out.println("Today is Wednesday");

break;

case THURSDAY:

System.out.println("Today is Thursday");

break;

case FRIDAY:

System.out.println("Today is Friday");

break;

case SATURDAY:

System.out.println("Today is Saturday");

break;

default:

break;

}

}

}

--------------

run result :

Today is Sunday

~~~

我们既实现了效果,又防止了 `obj.setX()` 方法中传入错误的值。现在当你写 `obj.setX(100)` 的时候,编译器就会发出警告。枚举确实很好用,但是在 Android 中,枚举又会造成新的问题:

因为 Enum 是一个完整的 Java 类,每个枚举的变量都是 Enum 类的对象,比方说我们刚才的代码中:

~~~

System.out.println(WeekDays.SUNDAY instanceof Enum);

-----------

run result:

true

~~~

所以使用枚举比我们一开始使用的 `public static final int SUNDAY = 0;` 形式消耗更多的内存。不过即使是在 Android 老的设备上(系统<=2.2),一些有关枚举性能的问题已经通过 JIT 编译器([简单了解 JIT]) 解决了,所以我们其实可以在 Android 上使用枚举。但是如果你的应用程序需要消耗很多的内存,或者你所开发的是游戏应用程序,那我们最好还是使用 `static final int` 常量的形式,不过正如开头所说,它容易出错,且没有办法限制传入的值。好在 Android 提供了一个支持库:

`com.android.support:support-annotations`

里面包括了很多好用的注解,也包含了可以解决我们目前的问题的注解:`IntDef` 和 `StringDef` ,它们可以代替枚举,可以在编译时就发现错误,并警告,现在我们来演示一下用法:

* 之前一直在写纯 Java 代码,所以可能使用的是 Android Studio 中的 Java 模块,记得切换到正常的 Android App 模块。

* 可根据[Android文档:导入支持库]

* 定义我们需要的常量:

~~~

public static final int SUNDAY = 0;

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;

~~~

* 声明注解**@WeekDays**,并为 **@IntDef** 传入这些常量,和枚举的做法有些像:

~~~

//这里使用 @IntDef 和 @Retention 来定义一个注解 @WeekDays

@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})

@Retention(RetentionPolicy.SOURCE)

public @interface WeekDays {}

~~~

* 声明 x 变量

~~~

@WeekDays

int x ;

~~~

* get/set 方法也使用 @WeekDays

~~~

public void setX(@WeekDays int x) { this.x = x;}

@WeekDays

public int getX() { return x;}

~~~

* 测试一下

~~~

@WeekDays int x ;

x = 60;//编译器会发出警告。

x = SUNDAY;//编译正常。

这里还有个问题要注意:

@WeekDays

int y =100;

//按刚才的说法,这里应该会报错,因为用 @WeekDays 修饰了变量 y ,而 100 明显不是 @IntDef 里所设定的值,

//但是经过测试,这里并不会报错。

//所以声明变量时,进行赋值是可以的。

//但是如果再想给 y 赋值,比如 y = 50; 这样的话是不行的。

//通过 setX 的方法赋值,也必须是 @IntDef 中所限定的值。

setX(60);//编译器会发出警告。

setX(SUNDAY);//编译正常。

//通过 getX 的方法 return 的值,也必须是 @IntDef 中所限定的值。

@WeekDays public int getX() { return x ;}//编译正常,因为 x 已经用 @WeekDays 修饰了。

@WeekDays public int getX() { return 60;}//编译器会发出警告。

@WeekDays public int getX() { return SUNDAY;}//编译正常。

@StringDef 和 @IntDef 的用法一样,只是适用的数据类型不同,所以就不演示用法了。

~~~

* 关于 @IntDef 的 flag 的含义

需要先了解 **Java 位运算符**,例如: >> , & , |

~~~

//这是 @IntDef 的源码,可以看到,我们还可以为 flag 赋值,默认是 false 的。

@Retention(SOURCE)

@Target({ANNOTATION_TYPE})

public @interface IntDef {

/** Defines the allowed constants for this element */

long[] value() default {};

/** Defines whether the constants can be used as a flag, or just as an enum (the default) */

boolean flag() default false;

}

//那我们定义 flag=true 作用是什么呢?

@IntDef(flag=true, value = {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})

//举个例子

public void setX(@WeekDays int x){}

//当 flag = false 的时候:

//注意:这里使用的 | ,&,^ 是位运算符,要和逻辑运算符区分开,不要搞混了。

setX(SUNDAY | MONDAY)//编译报错

//当 flag = true 的时候:

//我们可以将 value 使用位运算符计算,计算结果赋值给被 @WeekDays 修饰的变量

setX(SUNDAY | MONDAY)//编译通过

~~~

* 小问题

经过阅读 **关于 @IntDef 的 flag 的含义** ,我建议你可以先猜一下,**@StringDef** 可以设定类似的 `flag=true`或者是 `flag=false`吗?看一下 **@StringDef** 的源码,证实你的猜想。

##推荐扩展阅读

由于 Android 注解支持库也提供了其他很多注解,本篇文章介绍到的内容非常少,只能算是引出了 `com.android.support:support-annotations` 所以大家可以先学习注解的知识,然后再学习支持库中的注解的用法,共勉!

[Android 文档:使用注解改进代码检查](https://developer.android.com/studio/write/annotations.html)

[还在用枚举?我早就抛弃了!(Android 注解详解](http://www.jianshu.com/p/1fb27f46622c)

[Android文档:导入支持库]:https://developer.android.com/studio/write/annotations.html#adding-library

[简单了解 JIT]:http://blog.dontcareabout.us/2013/03/jit-compiler.html

[Java 枚举和 Android Typedef 注解]:https://noobcoderblog.wordpress.com/2015/04/12/java-enum-and-android-intdefstringdef-annotation/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值