4.3 注解(Annotation)

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')
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章