Java和Android中的注解

1.引言
从jdk1.5开始,引入了注解类Annotation,Annotation其实是一种接口,可以作用于类、方法、属性等,它可以通过反射机制来访问annotation信息,获取所加上注解信息,做相应的操作。相当于给相关的作用对象打上“tag”,使用方便,作用广泛。
2.java.lang中的注解
在java.lang中,用到的三种注解类,即常用到的Deprecated、Override和SuppressWarnings。
2.1@Deprecated过时
在使用AS编程的过程中,有一些方法写出来之后被画上了中划线,表示该方法已过时。@Deprecated注解起到的就是这个作用。
2.2@Override复写
这是开发过程中最常遇到的注解,表示复写父类中的方法。
2.3@SuppressWarnings阻止警告
阻止了弹出警告,比如屏蔽对上述过时的提示,可在调用
setOnPageChangeListener()
方法之上加上@SuppressWarnings("deprecation"),这样虽然在 IDE中仍以中划线形式表示,但如果使用javac命令就不再提示警告了。
3.元注解
那么以上的注解类的源码是什么样的呢,打开Override发现其代码如下:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
这里可以发现注解类的定义方法以及注解类上所加的注解—元注解。元注解有四个,位于java.lang.annotation包中:Documented,Inherited,Retention,Target。
3.1@Target
表示注解作用的目的
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Target {
ElementType[] value();
}
注解可以作用的目标有枚举类ElementType决定,可作用于类、方法、属性等,数组表示注解可以有多个作用域。
public enum ElementType {
ANNOTATION_TYPE,//注解类
CONSTRUCTOR,//构造方法
FIELD,//属性
LOCAL_VARIABLE,//局部变量
METHOD,//方法
PACKAGE,//包
PARAMETER,//用于描述参数
TYPE,//类、接口、注解类型或枚举
TYPE_PARAMETER,
TYPE_USE;
private ElementType() {
}
}
注解作用于类时,定义@Target(ElementType.TYPE)ElementType.TYPE表示类型,Class,Interface等都实现了java中的Type接口,因此ElementType.TYPE表示注解作用于这些“类”(并不是单纯的Class类)
3.2@Retention
表示注解的作用时段
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE})
public @interface Retention {
RetentionPolicy value();
}
有上面代码可见,Retention定义的是RetentionPolicy类型的数据,RetentionPolicy是一个枚举类型,包括SOURCE,CLASS,RENTIME三个类型,表示注解保留阶段。
SOURCE:表示注解只在源文件中保留。
CLASS:表示注解保留到.class文件中
RUNTIME:表示注解一直保留到内存中,类加载器把.class文件加载到内存中产生的字节码中要保留注解信息。
可想而知,@Override仅在写代码时用到,其Retention中的值为RetentionPolicy.SOURCE,@SuppressWarmings也只是编译器使用的,保留到SOURCE阶段。而@deprecated在内存中也需要保留,编译器需要得知方法是否过时,从加载到内存中的二进制文件中获取,因而要保留到RUNTIME阶段。
3.3@Documented
注解只是一个标记的话,那么使用javadoc生产文档时,这些注解都不会存在于文档中,要使注解在文档中也存在,就可以在使用了注解的作用对象上加上@Documented这个注解,javadoc所生产的文档就会带上注解信息。
3.4@Inherited
该注解表示子类可以集成加载父类上的注解,但是要注意:
1.注解定义在类上面,子类可以继承该注解
2.注解定义在方法上面,子类也可以继承该注解,但是如果子类复写了父类中定义了注解的方法,那么子类将无法继承该方法的注解,也就是说,子类在复写父类中被@Inherited标注的方法时,会将该方法上面的注解覆盖掉
3.Interface实现类无法继承接口中所定义的被@Inherited标注的注解
4.注解参数
在注解后为注解增加参数,如上述的@Retention、@Target后的括号中就是注解的参数。
参数的类型,支持基本数据类型,String类型,Class类型,enmu类型,Annotation类型以及上述所有类型的数据。
5.自定义注解
从上面的注解中,也大致看到了注解定义的方式。
1.使用@Interface定义一个注解类,其内部自行继承了Annotation类,
2.在该类中定义注解的参数,定义方式很像方法。
3.注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null,因此,使用空字符串或0作为默认值是一种常用做法。定义一些特殊的值,泪如空字符串或者负数,表示某个元素不存在参数设置默认值时,后面跟上default即可设置默认值。
4.当注解的参数只有一个时,建议用value作为参数名,这样在使用注解时,可以直接写参数的值接下来自定义一个注解类:

  1. @Documented

  2. @Target(ElementType.TYPE)

  3. @Retention(RetentionPolicy.RUNTIME)

  4. public @interface Car{

  5.  String name() default "";  
    
  6.  int number() default -1;  
    
  7. }
    在定义一个类去使用这个注解:

  8. @Car(name="好车",number=666)

  9. public class CarBMW(){

  10. }
    那么如何获取这些注解值呢?有如下方法:

  11. if(CarBMW.class.isAnnotationPresent(Car.class)){//判断CarBMW类是否有注解类Car

  12.  Car carAnnotation=(Car)CarBMW.class.getAnnotation(Car.class);//获取注解实例对象  
    
  13.  Log.v("Shawn",carAnnotation.name());//获取name参数的值  
    
  14.  Log.v("Shawn",carAnnotation.number());//获取number参数的值  
    
  15. }

6.Android中的注解
Annotation就是注解了,JDK1.5新增加的功能,该功能可用于类,构造方法,成员变量,参数等的声明中,比如常见的@Override,butterknife库里的@Bind,该功能并不影响程序的运行,主要作用就是提供类型安全,对编译器警告灯辅助工具产生影响。
Android从API16引入了annotation包,最常见两个注解@TargetApi和@SuppressLint,
@TargetApi(Build.VERSION_CODES.XX)用于屏蔽某一新api中才能使用的方法报的lint检查出现的错误;
@SuppressLinet(“NewApi")屏蔽一切新api中才能使用的方法报的Android lint错误。
这两个注解的作用仅仅是屏蔽lint错误,再发方法中还要根据版本不同做不同的操作。
6.1Nullness注解
包括@NonNull和@Nullable,先来看@NonNull源码:
/**

  • Denotes that a parameter, field or method return value can never be null.
  • <p>
  • This is a marker annotation and it has no specific attributes.
    */
    @Documented
    @Retention(CLASS)
    @Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
    public @interface NonNull {
    }
    Target中表示它可以应用于方法、参数、成员变量,使用@NonNull的好处就是避免后面频繁判断参数是否为空的操作。

6.2资源类型注解
此类注解以Res结尾,比如@BoolRes,@IdRes,@IntergerRes,@ColorRes等。
用法如下:
getDrawable(@DrawableRes int id)//getDrawable方法限定了传入的参数必须是Drawable资源文件

6.3@CallSuper
要求方法必须调用父类方法,可想而知,Activity的onCreate方法就有此注解标识。

6.4@idDef和@StringDef
提到最常用的Toast,在API21之前,一般可以这么写:
Toast.makeText(context, "msg", 0).show();
但是21之后,0突然被划红线了,查看源码发现,之前是这么写的:

  1. public static final int LENGTH_SHORT = 0;
  2. public static final int LENGTH_LONG = 1;
    makeText方法中单纯的写着int duration参数,而21之后,成了这样:
  3. @IntDef({LENGTH_SHORT, LENGTH_LONG})
  4. @Retention(RetentionPolicy.SOURCE)
  5. public @interface Duration {}
    在makeText的duration参数之前加上了注解@Duration,这就要求传入的Duration中的值才不会报警报。@IntDef和@StringDef中放入了一个value数组,在开发中,这两个注解就可以限制限制枚举了。

6.4进程类注解
@UIThread,@BinderThread,@MainThread,@WorkerThread
用来限定方法或类在指定的线程类型中被调用

6.5权限注解@RequiresPermission
如果方法的调用需要权限,可以加这个注解,当需要几个权限中的一个时,使用anyOf,如果@RequiresPermission(anyOf= { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION})
若需要多个权限,使用allOf,如@RequiresPermission(allOf = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
若需要单独的标注读和写的权限访问,可以用@Read或者@Write标注每一个权限需求。

6.6@SdkConstant
表示一个常量字段应该被输出在SDK工具中使用,例如:
添加一个自定义的Action

  1. @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)

  2. public static final String ACTION_MY_TEST = "android.intent.action.MY_TEST";
    则可以这样使用

  3. Intent myTest = new Intent(Intent.ACTION_MY_TEST);

  4. mContext.sendBroadcast(myTest);

6.7范围约束@FloatRange、@IntRange和@Size
前两个限制了数字的范围,比如可以用来限制传入参数值的范围,
@Size可以用来限定集合的大小或者限定字符串的长度,还可以做其他限制:1.限制最小最大数量:@Size(min=1,max=10)
2:数量必须是2的倍数(偶数):@Size(multiple=2)

6.8@CheckResult
该注解意味着需要对方法的返回值进行处理,例如:有个方法为:

  1. @CheckResult
  2. public boolean checkValid(String value){
  3.  return TextUtils.isEmpty(value);  
    
  4. }
    当调用者直接调用checkValid(”abc”)时会报错,需要对方法的返回值进行处理,无论返回true或false,需要进行后续操作,不能单单的调用一句。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容