在开始之前,我们需要声明一件重要的事情是:我们不是在讨论在运行时通过反射机制运行处理的注解,而是在讨论在编译时处理的注解。
编译时注解跟运行时注解到底区别在什么地方?其实说大也不大,主要是考虑到性能上面的问题。运行时注解主要是完全依赖于反射,反射的效率比原生的慢,所以在内存比较少,CPU比较烂的机器上会有一些卡顿现象出现。而编译时注解完全不会有这个问题,因为它在我们编译过程(java→类)中,通过一些注解标示,去动态生成一些类或者文件,所以跟我们的APK运行完全没有任何关系,自然就不存在性能上的问题,所以一般比较著名的开源项目如果采用注解功能,通常采用编译时注解
注解处理器是javac自带的一个工具,用来在编译时期扫描处理注解信息。你可以为某些注解注册自己的注解处理器。这里,我假设你已经了解什么是注解及如何自定义注解。如果你还未了解注解的话,可以查看官方文档。注解处理器在Java 5的时候就已经存在了,但直到Java 6(发布于2006看十二月)的时候才有可用的API。过了一段时间Java的使用者们才意识到注解处理器的强大,所以最近几年它才开始流行。
一个特定注解的处理器以java源代码(或者已编译的字节码)作为输入,然后生成一些文件(通常是。java文件)作为输出。那意味着什么呢?你可以生成java代码!这些java代码在生成的。java文件中,因此你不能改变已经存在的java类,例如添加一个方法。这些生成的java文件跟其他手动编写的java源代码一样,将会被javac编译。
注解处理是在编译阶段执行的,它的原理就是读入Java源代码,解析注解,然后生成新Java的代码。新生成的Java代码最后被编译成Java字节码,注解解析器(注解处理器)不能改变读入的Java类,比如不能加入或删除Java方法。
让我们来看一下处理器的API。所有的处理器都继承了AbstractProcessor,如下所示:
com . example,包 进口java.util.LinkedHashSet; 进口java.util.Set; 进口javax.annotation.processing.AbstractProcessor; 进口javax.annotation.processing.ProcessingEnvironment; 进口javax.annotation.processing.RoundEnvironment; 进口javax.annotation.processing.SupportedAnnotationTypes; 进口javax.annotation.processing.SupportedSourceVersion; 进口javax.lang.model.SourceVersion; 进口javax.lang.model.element.TypeElement; 公开课MyProcessor延伸AbstractProcessor { @Override 公共逻辑过程(Set<& # 63;TypeElement>延伸;annoations, RoundEnvironment env) { 返回错误; } @Override 公共SetgetSupportedAnnotationTypes () { Set annotataions=new LinkedHashSet (); annotataions.add (“com.example.MyAnnotation”); 返回annotataions; } @Override 公共SourceVersion getSupportedSourceVersion () { 返回SourceVersion.latestSupported (); } @Override 公共同步空白init (ProcessingEnvironment processingEnv) { super.init (processingEnv); } }
init (ProcessingEnvironment processingEnv):所有的注解处理器类都必须有一个无参构造函数。然而,有一个特殊的方法init(),它会被注解处理工具调用,以ProcessingEnvironment作为参数.ProcessingEnvironment提供了一些实用的工具类元素,类型和纳税人。我们在后面将会使用到它们。
<代码>过程(Set<& # 63;TypeElement>延伸;annoations RoundEnvironment env) 代码>,:这类似于每个处理器的主要()方法。你可以在这个方法里面编码实现扫描,处理注解,生成java文件。使用RoundEnvironment参数,你可以查询被特定注解标注的元素(原文:您可以查询元素与某个注释注释)。后面我们将会看到详细内容。
<代码> getSupportedAnnotationTypes(): 代码>在这个方法里面你必须指定哪些注解应该被注解处理器注册。注意,它的返回值是一个字符串集合,包含了你的注解处理器想要处理的注解类型的全称。换句话说,你在这里定义你的注解处理器要处理哪些注解。
<代码> getSupportedSourceVersion() 代码>:用来指定你使用java版的本。通常你应该返回<代码> SourceVersion.latestSupported()> 代码。不过,如果你有足够的理由坚持用java 6的话,你也可以返回<代码> SourceVersion.RELEASE_6> 代码。我建议使用<代码> SourceVersion.latestSupported()> 代码。在java 7中,你也可以使用注解的方式来替代重写