注解的定义
在Java中,要声明一个注解很简单,只要你会使用接口,你就一定会使用注解,以下是一个简单的注解的例子:
public @interface Table{
// add code to yourself
}
聪明的你一定会发现,把接口变成注解只需要再interface前增加一个@符号就可以了.
Java中的元注解
@Target
Target注解声明了Annotation所修饰对象的范围,它可携带的参数可枚举如下:
public enum ElementType {
/**类|接口|枚举类型
*Class, interface (including annotation type), or enum declaration */
TYPE,
/**成员变量 包括枚举常量
*Field declaration (includes enum constants)*/
FIELD,
/** 方法声明 Method declaration */
METHOD,
/** 形参声明 Formal parameter declaration */
PARAMETER,
/** 构造函数 Constructor declaration */
CONSTRUCTOR,
/** 局部变量 Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** 包 Package declaration */
PACKAGE,
/**
* Type parameter declaration *
* @since 1.8 java 1.8 以上新增支持
* @hide 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
* @since 1.8 java 1.8 以上新增支持
* @hide 1.8
*/
TYPE_USE
}
@Retention
该注解主要是声明Annotation被保留的时间线,有些Annotation值保留在源码中,有些Annotation 会被编译到class文件中,而有些Annotation会被JVM所读取,这些都是@Retention在起控制作用。
public enum RetentionPolicy {
/**存在于源码中,注解将被编译器丢弃*/
SOURCE,
/** 注解会被编译到CLASS文件中,注解将被编译器记录到类文件中,但在运行时将被VM所丢弃/
CLASS,
/**它会一直保留到VM运行时,因此它可以被反射机制所捕获*/
RUNTIME
}
@Documented
需要被javadoc所记录
@Inherited
该注解 声明了某个被标注的类型是被继承,如果一个使用Inherited的注解被用于<b>Class</b>中,那么它的子类也会继承这个注解.
解析注解
使用以下方法可以访问Annotation的注解信息
/**注解属性是否是指定类型*/
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType)
/**返回指定类型的注解*/
public <A extends Annotation> A getAnnotation(Class<A> annotationType)
/**返回所有的注解(该方法将忽略继承到的注解类型)*/
public native Annotation[] getDeclaredAnnotations()
/**返回所有的注解(该方法将包含继承到的注解类型)*/
public Annotation[] getAnnotations()
代码实现
package com.deity.application.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
* Created by Deity on 2017/2/8.
*/
@SuppressWarnings("unused")
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HumanAnnotation {
/**访问权修饰符 public 或者 protect*/
String userName() default "还未起名字";
String getMyBrithday() default "2016-09-10 10:00:00";
int getMyAge() default 1;
}
package com.deity.application.annotation;
/**
* 女儿
* Created by Deity on 2017/2/8.
*/
public class Daughter {
/**起个响亮的名字*/
private String userName;
/**生日*/
private String birthday;
/**年龄*/
private int age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
@HumanAnnotation(userName = "小宝宝",getMyBrithday = "2016年2月8日22:11:50",getMyAge = 2)
public String toString() {
String result = "这是我女儿>>>姓名:"+userName+" 年龄:"+age+" 出生日期:"+birthday;
return result;
}
}
package com.deity.application;
import com.deity.application.annotation.Daughter;
import com.deity.application.annotation.HumanAnnotation;
import org.junit.Test;
import java.lang.reflect.Method;
/***
* 自定义注解测试
*/
public class ExampleUnitTest {
@Test
public void AnnotationTest(){
Daughter daughter = new Daughter();
Method[] fields = Daughter.class.getDeclaredMethods();
for (Method field:fields){
if (field.isAnnotationPresent(HumanAnnotation.class)) {
HumanAnnotation humanAnnotation = field.getAnnotation(HumanAnnotation.class);
daughter.setAge(humanAnnotation.getMyAge());
daughter.setBirthday(humanAnnotation.getMyBrithday());
daughter.setUserName(humanAnnotation.userName());
}
}
System.out.println(daughter.toString());
}
}
实现一个编译时注解
package com.example;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解Demo
* Created by Deity on 2017/2/8.
*/
@SuppressWarnings("unused")
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HumanMessageAnnotation {
/**public Or protect*/
String userName() default "unknow";
String getMyBrithday() default "2016-09-10 10:00:00";
int getMyAge() default 1;
}
注解器实现:
package com.example;
import com.google.auto.service.AutoService;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.annotation.processing.Processor;
/**
* 1.继承 AbstractProcessor
*/
//@SupportedSourceVersion(SourceVersion.RELEASE_6) 1
//@SupportedAnnotationTypes("com.example.HumanMessageAnnotation") 2
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor{
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
/**
* {@inheritDoc}
*
* @param annotations
* @param roundEnv
* @return true
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(HumanMessageAnnotation.class)) {
if (ElementKind.METHOD == element.getKind()){
ExecutableElement typeElement = (ExecutableElement ) element;
System.out.println(typeElement.getAnnotation(HumanMessageAnnotation.class).userName()+"\n"+
typeElement.getAnnotation(HumanMessageAnnotation.class).getMyBrithday()+"\n"+
typeElement.getAnnotation(HumanMessageAnnotation.class).getMyAge());
}
}
return false;
// for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
// System.out.println("------------------------------");
// if (element.getKind() == ElementKind.CLASS) {
// TypeElement typeElement = (TypeElement) element;
// System.out.println(typeElement.getSimpleName());
// System.out.println(typeElement.getAnnotation(MyAnnotation.class).value());
// }
// System.out.println("------------------------------");
// }
// return false;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> annotations = new LinkedHashSet<>();
annotations.add(HumanMessageAnnotation.class.getCanonicalName());//基础类的规范名称
return annotations;
// Set<String> annotataions = new LinkedHashSet<String>();
// annotataions.add(MyAnnotation.class.getCanonicalName());
// return annotataions;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
扩展
javax.lang.model.element 中 Element 的子接口
................................................................................................................
interface ExecutableElement
表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。
interface PackageElement
表示一个包程序元素。
interface TypeElement
表示一个类或接口程序元素。
interface TypeParameterElement
表示一般类、接口、方法或构造方法元素的形式类型参数。
interface VariableElement
表示一个字段、enum常量、方法或构造方法参数、局部变量或异常参数。
注解处理器的注册
手动注册注解处理器
1、在 processors 库的 main 目录下新建 resources 资源文件夹;
2、在 resources文件夹下建立 META-INF/services 目录文件夹;
3、在 META-INF/services 目录文件夹下创建 javax.annotation.processing.Processor 文件;
4、在 javax.annotation.processing.Processor 文件写入注解处理器的全称,包括包路径;
使用AutoService 实现注解处理器的注册
compile 'com.google.auto.service:auto-service:1.0-rc3'
使用APT
在工程build.gradle上,增加依赖
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' // add
在module上增加依赖
apply plugin: 'com.neenbedankt.android-apt' // add
dependencies {
//.............
compile project(':annotations')
apt project(':processor')
}
参考:
深入理解Java:注解Annotation自定义注解入门
APT(Annotation Processing Tool) 原理
APT 是一种处理注释的工具,对Android开发者来说,市面上比较出名的就是android-apt,但是android-apt,从Android Studio 2.2开始,Google已经内置了一款APT插件,那就是annotationProcessor,目前android-apt已宣布android-apt完成它的历史使命,并推荐大家使用官方annotationProcessor插件.