目录
1.注解
注解(Annotation)也被称为元数据(Metadata),是在Java SE 5中提供的一个新特性。Annotation可以用来修饰类,属性,方法。在Java中,除了使用系统内置的Annotation以外,用户还能够通过自定义Annotation来实现所需要的功能。下面就来看一下如何使用自定义的Annotation。
又分为标准注解和元注解。
1.1 标准注解
- @Override:对覆盖超类中的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编 译器会发出错误警告。
- @Deprecated:对不鼓励使用或者已过时的方法添加注解,当编程人员使用这些方法时,将会在编译 时显示提示信息。
- @SuppressWarnings:选择性地取消特定代码段中的警告。
- @SafeVarargs:JDK 7新增,用来声明使用了可变长度参数的方法,其在与泛型类一起使用时不会出现 类型安全问题
1.2 元注解
在Java中目前包含及四种元注解。元注解是专门用来负责注解其他的注解。所以自定义注解也是通过元注解来完成的。首先在这里来看一下Java中的四种元注解。
@Target
注解所修饰的对象范围。
其中的ElementType取值如下:
TYPE:类,接口或者是enum声明
FIELD:域声明(包括enum实例)
METHOD:方法声明
PARAMETER:参数声明
CONSTRUCTOR:构造器声明
LOCAL_VARIABLE:局部变量声明
ANNOTATION_TYPE:注解类型声明
PACKAGE:包声明
@Retention
用来声明注解的保留策略
其中RetentionPolicy取值如下:
SOURCE:只在源码中保留,该注解将会被编译器丢掉
CLASS:注解在class文件中可用,但是会被VM丢弃
RUNTIME:VM会在运行时保留注解,这时可以通过反射读取注解信息。
@Documented
表示在Javadocs中包含这个注解。
@Inherited
表示允许子类继承父类中的注解
2.定义注解
2.1 基础定义
定义新的注解类型使用@interface关键字,
public @interface Swordman{
String name() default "李丹";
int age() default 22;
...
}
简单使用
@Swordman(name ="张三",age=11)
public class AnnotationTest{
...
}
2.2 定义运行时注解
可以用@Retention来设定注解的保留策略,这 3 个策略的生命周期长度为 SOURCE <CLASS< RUNTIME
@Retention(RetentaionPolicy.RUNTIME)
public @interface Swordman{
String name() default "李丹";
int age() default 22;
...
}
2.3 定义编译时注解
@Retention(RetentaionPolicy.CLASS)
public @interface Swordman{
String name() default "李丹";
int age() default 22;
...
}
3.注解处理器
不同的注解有不同的注解处理器。 虽然注解处理器的编写会千变万化,但是其也有处理标准,比如:针对运行时注解会采用反射机制处理, 针对编译时注解会采用 AbstractProcessor 来处理
3.1 编译时注解
3.1.1 定义注解
使用Android studio 新建一个java Library ,这个Library名为annotations 存放注解。
@Retention(RetentaionPolicy.CLASS)
@Target(FIELD) // 修饰变量
public @interface BindView{
int age() default 1;
...
}
3.1.2 编写注解处理器
再新建一个Java Library来存放注解处理器,这个Library名为processor。我们来配置 processor库的build.gradle
dependencied{
compile fileTree(include:['*.jar'],dir:'libs')
compile project(':annotaions')
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
public class ClassProcessor extends AbstractProcessor {
/**
* 初始化
* @param processingEnv
*/
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
Filer filer = processingEnv.getFiler();
Messager messager = processingEnv.getMessager();
Elements elementUtils = processingEnv.getElementUtils();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return super.getSupportedSourceVersion();
}
}
- init:被注解处理工具调用,并输入 ProcessingEnviroment 参数。ProcessingEnviroment提供很多有用的 工具类,比如Elements、Types、Filer和Messager等。
- process:相当于每个处理器的主函数main(),在这里写你的扫描、评估和处理注解的代码,以及生 成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。
- getSupportedAnnotationTypes:这是必须指定的方法,指定这个注解处理器是注册给哪个注解的。注 意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
- getSupportedSourceVersion:用来指定你使用的 Java 版本,通常这里返回 SourceVersion.latestSupported()。
参考:Android 进阶之光
3.1.3 注册–注解解析器
使用谷歌开源的AutoService,它用来帮助开 发者生成META-INF/services/javax.annotation.processing.Processor文件。首先我们添加该开源库,可以在 File→Project Structure 搜索“auto-service”查找该库并添加
最后在注解处理器ClassProcessor中添加@AutoService 就可以了。
@AutoService(Processor.class)
public class ClassProcessor extends AbstractProcessor {
}
3.2 运行时注解
运行时解析需要用到反射机制。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Get {
String url() default "";
}
//使用
public class ApiSevice {
@Get(url = "baidu.com")
public String getNetData(){
return null;
}
}
代码动态获取
Method[] declaredMethods = ApiSevice.class.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
Method method = declaredMethods[i];
Get annotation = method.getAnnotation(Get.class);
String url = annotation.url();
Log.d(TAG, "onCreate: "+url);
}
3.4 应用注解
在主项目build.gradle文件里添加依赖
implementation project(path: ':annotation')
implementation project(path: ':processor')
然后重新编译整个工程。
主项目引用的processor只在编译的时候起到实际作用,比如打包,运行的时候没有必要引用,怎么解决呢?
接下来我们引入android-apt插件就能解决这个问题。
1.在工程的build.gradle里添加
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
2.更改依赖
apply plugin:'com.neenbedankt.android-apt'
...
deoebdebcies{
...
apt project(path: ':processor')
}