1. 问题起源
那天写代码的过程中,switch使用枚举类作为条件时,突然出现了一个报错
枚举 switch case 标签必须为枚举常量的非限定名称
public class UsbMsg {
private MsgType mMsgType;
// 这是我的枚举
public enum MsgType {
MOUNT,
UNMOUNT,
BAD_REMOVAL,
REMOVED
}
public MsgType getMsgType {
return mMsgType;
}
}
// 这是使用时的代码
switch (usbMsg.getMsgType()) {
case MsgType.MOUNT: // 报错行
case MsgType.UNMOUNT: {
showUsbList(volumes);
break;
}
}
[黑人问号脸.jpg] 这是哪儿错了???一番百度之后发现,人家写的很明白了,直接用enum里面的名称,把MsgType去掉,不用限定,因为你的switch里面已经限定是这个枚举类里面的值了!
后来就跟同事吐槽了一下,然后同事为我打开了新世界大门,他说他一般不用枚举,用注解的方式!仿照android原生VISIBLE/INVISIBLE/GONE的写法!!高级了一下!
2. 为什么不使用枚举?
找了一篇文章==>Android官方不建议使用枚举的原因,大概原因就是因为枚举本身是一个类,编译后会对每一种定义的类型生成相应对象,相对于静态常量来讲,消耗了很多内存。如果只是单纯的想做类型限定的话,完全没必要使用枚举。
3. 如何使用注解替代枚举?
下面我们来看一下,android原生是怎么写的?
/** @hide */
@IntDef({VISIBLE, INVISIBLE, GONE}) // Visibility的类型限定
@Retention(RetentionPolicy.SOURCE) // 注解只存在于源码编译期
public @interface Visibility {}
/**
* This view is visible.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int VISIBLE = 0x00000000;
/**
* This view is invisible, but it still takes up space for layout purposes.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int INVISIBLE = 0x00000004;
/**
* This view is invisible, and it doesn't take any space for layout
* purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int GONE = 0x00000008;
首先定义了几个常量类型,之后定义了一个注解名为Visibility,使用了两个注解,@IntDef用来限定Visibility中int类型常量的值(默认情况下值不可重复,编辑器会报错,若一定要重复如更新一个变量名,但又要保持向下兼容,就可以使用@SuppressLint(“UniqueConstants”)拒绝类型检查),@Retention用来限定该注解存在于源码时期,一般用来做一些源码检查操作。
在使用时,我们可以像下面一样将注解加在参数上,这样就可以像Enum一样对参数进行类型限制。值得注意的是,这样的类型检查只会在编译器中进行提醒,并不会影响编译过程,如果你无视提醒直接运行那么也是不会报错的。
public void setVisibility(@Visibility int visibility) {
setFlags(visibility, VISIBILITY_MASK);
}
那么下面我们仿照Android原生的代码修改一下之前的代码,就会变成这样
public class UsbMsg {
private int mMsgType;
// 这是我的注解
@IntDef({MOUNT, UNMOUNT, BAD_REMOVAL, REMOVED})
@Retention(RetentionPolicy.SOURCE)
public @interface MsgType {
}
public static final int MOUNT = 0x0;
public static final int UNMOUNT = 0x2;
public static final int BAD_REMOVAL = 0x4;
public static final int REMOVED = 0x8;
@MsgType
public int getMsgType() {
return mMsgType;
}
}
switch (usbMsg.getMsgType()) {
case UsbMsg.MOUNT: {
break;
}
case UsbMsg.UNMOUNT: {
break;
}
default: {
break;
}
}
注意到@IntDef这个注解并不是默认提供的,是在support包中的,所以使用的话需要引入一下包compileOnly ‘com.android.support:support-annotations:28.0.0’,包版本根据你的compileSdkVersion来,另外他还有个好兄弟可以做String类型的限定 - @StringDef。最后查找资料过程中发现一个写的不错的文章,推荐下==>Android中不使用枚举类(enum)替代为@IntDef @StringDef