带你进一步学习注解

在很多程序设计语言里,依赖注入是一种比价流行的设计模式,在Android开发中很多框架也是采用的是依赖注入的方式,比如说我们常用框架ButterKnife和Dagger2。我们只是知道如何使用,但是有多少程序猿了解其原理,这些框架都是采用编译时注解。

什么是注解

 从JDK 5开始,Java增加了注解,注解是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。

注解分类

 注解分为标准注解和元注解。

1.标准注解

 标准注解有4中:

  1. @Override:对覆盖父类中的方法进行标记,如果被标记的方法并没有实际重写父类中的方法,则编译器会发出错误警告。
  2. @Deprecated:对已过世的方法添加注解,当程序猿使用这些方法时,将会在编译时显示提示信息。
  3. SuppressWarning:选择性的忽略代码中的警告,通常使用方式有以下忽略方式:
deprecation -- 使用了不赞成使用的类或方法时的警告

unchecked -- 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。

fallthrough -- 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。

path -- 在类路径、源文件路径等中有不存在的路径时的警告。

serial -- 当在可序列化的类上缺少 serialVersionUID 定义时的警告。

finally -- 任何 finally 子句不能正常完成时的警告。

all -- 关于以上所有情况的警告。
  • SafeVarargs:JDK 7新增,用来声明使用了可变长度参数的方法,其在与泛型类一起使用时不会出现类型安全问题。

2.元注解

 除了标注注解,还有元注解,它用来注解其他注解,从而创建新的注解。元注解有以下几种:

  1. @Targe:表示所修饰的对象使用范围。
  2. @Inherited:表示注解可以被继承;但并不是注解本身可以继承,而是说一个父类被@Inherited注解过,它的子类没有被任何注解应用的话,那么这个子类就继承了父类的注解。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}

@Test
public class A {}

//Class B 也含有注解@Test
public class B extends A {}
  • @Documented:表示这个注解应该被JavaDoc工具记录。
  1. @Retention:用来声明注解的保留策略。
  2. @Repeatable:JDK 8新增,允许一个注解在同一个声明类型(类、属性或方法)上多次使用。
@interface Users {
    User[]  value();
}

@Repeatable(Users.class)
@interface User{
    String name default "";
}

@Person(name="artist")
@Person(name="coder")
@Person(name="PM")
public class SuperUser{
}
  • @Repeatable注解了User,而括号里的类相当于一个容器注解Users(用来存放其它注解的地方,其本身是一个注解).注解Users属性是一个数组。

 在我们自己自定义注解中,用到最多是@Targe和@Retention注解,我们重点讲解。

 @Targe的参数是ElementType类型的值,其源码如下:

public enum ElementType {

    /** Class, interface (including annotation type), or enum declaration */
    //能修饰类、接口或枚举类型
    TYPE,

    /** Field declaration (includes enum constants) */
    //能修饰成员变量或枚举中的常量
    FIELD,

    /** Method declaration */
    //能修饰方法
    METHOD,

    /** Formal parameter declaration */
    //能修饰参数
    PARAMETER,

    /** Constructor declaration */
    //能修饰构造方法
    CONSTRUCTOR,

    /** Local variable declaration */
    //能修饰局部变量
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    //能修饰注解
    ANNOTATION_TYPE,

    /** Package declaration */
    //能修饰包
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    //类型参数声明
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    //使用类型
    TYPE_USE
}
  • 对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性。

 @Retention注解有三种类型,分别表示不同级别的保留策略。保留策略可以理解为生命周期,表示注释信息存留时间的长短。其参数是RetentionPolicy枚举值。其RetentionPolicy的源码如下:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
  • RetentionPolicy.SOURCE:源码级注解。注解信息只会保留在.java源码中,源码在编译后,注解信息被丢失,不会保留在.class中。
  • RetentionPolicy.CLASS:编译时注解。注解信息会保留在.java源码以及.class中。当运行Java程序时,JVM会丢弃该注解信息,不会保留在JVM中。
  • RetentionPolicy.RUNTIME:运行时注解。当运行Java程序时,JVM也会保留该注解信息,可以通过反射获取该注解信息。

 每1个Annotation对象,都会有唯一的RetentionPolicy属性。以上的注解的生命周期长短时间:SOURCE < CLASS < RUNTIME。

自定义注解

 下面通过自定义一个防重复点击的注解,clickIntervals为防重复点击的时间。

  • 基本定义

 自定义一个注解只需要使用@interface关键字,实例如下:

public @interface SingleClick {

}
  • 定义成员变量

 注解只有成员变量,没有方法。注解的成员变量在注解定义中以“无形参的方法”形式来声明,其“方法名”定义了该成员变量的名字,其返回值定义了该成员变量的类型。

public @interface SingleClick {
    /**
     * 设置防重复点击时间
     * @return 防重复点击时间,若没有设置默认为1s
     */
    long clickIntervals() default 1000;
}

使用关键字default设置默认值

  • 定义注解的使用范围

 通过@Targe来声明其使用的范围,比如下面使用在方法上面,使用ElementType.METHOD进行声明;如果使用在类或接口上面,则采用ElementType.TYPE。根据上面ElementType枚举值的含义,选择自己需要的枚举值。

@Target(ElementType.METHOD)
public @interface SingleClick {
    /**
     * 设置防重复点击时间
     * @return 防重复点击时间,若没有设置默认为1s
     */
    long clickIntervals() default 1000;
}
  • 定义注解的保留策略

 实际是设置注解的生命周期,根据自己场景的需要,适当的选择其保留策略。因为防重复点击是程序运行时的操作,则应该定义运行时注解。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SingleClick {
    /**
     * 设置防重复点击时间
     * @return 防重复点击时间,若没有设置默认为1s
     */
    long clickIntervals() default 1000;
}
  • 上面可以说已经定义了一个有效的注解,看一下使用方式:
@SingleClick(clickIntervals = 3000)
public void firstOnClick(View view) {
    Log.e(TAG, "firstOnClick: ");
}
  • 因为注解SingleClick我声明使用范围方法上,所以只能在方法上使用,clickIntervals = 3000 代表3s内防重复点击。

注意只是靠一个注解,是不能完成防重复点击,需要结合AOP变成才能真正的防重复点击的功能。

 注解SingleClick是一个运行时注解,我们也可以采用源码级注解进行一些检查性工作,比如 @Override 和 @SuppressWarnings 都是采用RetentionPolicy.SOURCE,其源码如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional warning names they support in conjunction with this
     * annotation type. They are encouraged to cooperate to ensure
     * that the same names work across multiple compilers.
     * @return the set of warnings to be suppressed
     */
    String[] value();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值