美文网首页
Java和Android中的注解

Java和Android中的注解

作者: 明明_白_白 | 来源:发表于2018-09-14 11:44 被阅读13次

    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,需要进行后续操作,不能单单的调用一句。

    相关文章

      网友评论

          本文标题:Java和Android中的注解

          本文链接:https://www.haomeiwen.com/subject/afqogftx.html