注解
元注解
定义
注解类也能使用其他的注解声明,在JDK1.5中提供了用来对注解类型进行注解的注解类,我们称为元注解(meta-annotation).
- @Target:作用于哪些节点,是个数组可传多个
- ElementType.ANNOTATION_TYPE 可以应用于注解类型。
- ElementType.CONSTRUCTOR 可以应用于构造函数。
- ElementType.FIELD 可以应用于字段或属性。
- ElementType.LOCAL_VARIABLE 可以应用于局部变量。
- ElementType.METHOD 可以应用于方法级注解。
- ElementType.PACKAGE 可以应用于包声明。
- ElementType.PARAMETER 可以应用于方法的参数。
- ElementType.TYPE 可以应用于类的任何元素。
- @Retention : 保留级别
- RetentionPolicy.SOURCE 标记的注解仅保留在源码级别中,并被编译器忽略。(在class文件里是看不到注解的存在)。
- RetentionPolicy.CLASS 标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略。(Android里用的是dex,class打包成dex之后,注解会被抛弃)
- RetentionPolicy.RUNTIME 标记的注解由 JVM 保留,因此运行时环境可以使用它。
SOURCE < CLASS < RUNTIME,即CLASS包含了SOURCE,RUNTIME包含SOURCE、CLASS。 默认是class级别。
常见配合使用场景
注解声明
- @interface : 声明注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface AnnotationTest {
}
元注解
- IntDef 为例
限制参数取值范围时可替代枚举的使用,枚举比较耗内存。
// CountryType.java
public class CountryType {
public static final int CHINA = 1;
public static final int AMERICA = 2;
}
// Country.java
@IntDef({CountryType.CHINA, CountryType.AMERICA}) // IntDef 为元注解,可作用于注解上。country的取值
@Target(ElementType.PARAMETER) // 此注解 在方法参数上
@Retention(RetentionPolicy.SOURCE) // 源码级别的
public @interface Country {
}
// 使用
setCountry(CountryType.CHINA);
private void setCountry(@Country int countryType){
}
此时可以看下编译后的class文件,source级别的注解,在class级别是否被保留。
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(2131427356);
this.setCountry(1);
}
private void setCountry(int countryType) { // 注解未被保留
}
APT 注解处理器
APT 全称Annotation Process Tools。编写好的Java源文
件,需要经过 javac 的编译,翻译为虚拟机能够加载解析的字节码Class文件。注解处理器是 javac 自带的一个工
具,用来在编译时期扫描处理注解信息。你可以为某些注解注册自己的注解处理器。 注册的注解处理器由 javac
调起,并将注解信息传递给注解处理器进行处理。
常见使用APT的开源框架:glide arouter butterknife …
APT结合注解的使用
- 创建两个java 模块。一个annotation 存放注解,一个compiler存放注解处理器。注意这里是java library
- 创建注解
- 创建注解处理器 并依赖注解模块
- 注册注解处理器
- 主模块依赖注解和注解处理器,并引用注解
详细代码如下:
- annotation library:注解
package com.by.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) // 此注解作用在类上 @Retention(RetentionPolicy.SOURCE) // 源码级别的 public @interface MyClass { }
- compiler library:注解处理器
-
在注解处理器模块,引用注解liabry
implementation project(':annotation')
-
声明注解处理器
@SupportedAnnotationTypes({"com.by.annotation.MyClass"}) // 需要处理的注解,这里也可以重写方法 public class MyClassProcess extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { Messager messager = processingEnv.getMessager(); messager.printMessage(Diagnostic.Kind.NOTE, "走到注解处理器"); // 这里的打印 不要是error 级别的, 不然会崩溃 return false; } }
-
注册注解处理器
标红处的目录结构不能变,这里是注解处理器的注册路径。
-
app 模块
引用注解和注解处理器,并使用
annotationProcessor project(':compiler') implementation project(':annotation') @MyClass public class CountryActivity extends AppCompatActivity { }
运行结果
The following annotation processors are not incremental: compiler.jar (project :compiler). Make sure all annotation processors are incremental to improve your build speed. 警告: No SupportedSourceVersion annotation found on com.by.compiler.MyClassProcess, returning RELEASE_6. 警告: 来自注释处理程序 'org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor' 的受支持 source 版本 'RELEASE_6' 低于 -source '8' 注: 走到注解处理器 注: 走到注解处理器