Annotation注解学习
在Retrofit中,的核心技术之一就是使用Java中的Annotation注解来提供Http的各种信息,我们很有必要总结一下
定义
注解是Java代码里的特殊标记,这些标记可以在编译 、类加载、运行时被读取,并执行相应的处理。
作用
通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充歇息进行验证或者进行部署。
特点
- 就跟修饰符一样使用,可以修饰包、构造器、方法、成员变量、参数、局部变量的声明
- Annotation不能影响程序代码的执行,无论增加、删除Annotation,代码都始终如一的执行。
- 如果希望让程序中的Annotation能在运行时起一定的作用,只有通过某种配套的工具对Annotation中的信息进行访问和处理,访问处理Annotation的工具统称为APT(Annotion Processing Tool)
用法
-
定义
-
不带成员变量的
public @interface Test{}
它是继承Annotation接口的
-
带成员变量的
public @interface Test{ //定义了两个成员变量的Annotation //Annotation中的成员变量以方法的形式来定义 String name(); int age(); }
在使用的时候,可以@Test(name=“xx”,age=10) 给属性赋值,可以给属性设置默认值
public @interface Test{ //定义了两个成员变量的Annotation //Annotation中的成员变量以方法的形式来定义 String name() default ”liujian“; int age() default 10; }
-
使用@interface定义的Annotation的确非常像一个注释接口,这个注释接口即成了Annotation接口,这点可以通过反射来看到Test接口里面包含了Annotation接口里的方法。
-
使用
- 直接使用
@Test public class MyClass { @Test Integer a = 10; @Test public static void main(@Test String[] args) { @Test int a = 10; } }
测试结果:Test可以修饰 类、成员变量、方法、参数、局部变量声明。
注意:修饰包会报错
-
限制使用
-
阶段限制
-
直接决定我们是否可以在程序运行起来后可以获取到注解信息并做处理,还是只能在编译阶段使用。
使用:JDK的@Retention 注解来修饰我们定义的Annotation
-
@Retention(RetentionPolicy.RUNTIME) public @interface Test { }
public enum RetentionPolicy { SOURCE, CLASS, RUNTIME; private RetentionPolicy() { }
-
SOURCE: 编译器直接丢弃,没啥用途
CLASS 编译器将把注释记录在class文件中,当运行java程序时,JVM不再保留注释
安卓中著名的ButterKnife就使用的CLASS,可以在编译阶段动态生成Java代码
@Retention(CLASS) @Target(FIELD)
public @interface BindView {
/** View ID to which the field will be bound. */
@IdRes int value();
}
RUNTIME: 编译器将把注释记录在class文件中,当运行java程序时,JVM也会保留注释,程序可以通过反射获取 该注释
Retrofit就是使用的RUNTIME来定义注解的,然后时候Java的动态代理
-
修饰程序元素限制
@Target :用于指定被修饰的Annotation能用于修饰那些程序元素
@Target(ElementType.FIELD) public @interface Test { }
Target 源码
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface Target { ElementType[] value(); }
ElementType.ANNOTATION_TYPE的源码
public enum ElementType { TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE; private ElementType() { } }
不难看出Target可以同时设置多个参数,可以同时修饰多个累的成员
还有两个专门修饰自定义Annotation的JDK自带的注解@Documented和Inherited由于特别不重要,我们就不提了