1.概念
注解能够添加到Java源代码的语法元数据。类,方法,变量,参数,包都可以被注解,可用来将信息元数据与程序元素进行关联。
2.作用
a.标记,用于告诉编译器一些信息
b.编译时动态处理,如动态生成代码
c.运行时动态处理,如得到注解信息.
这里的三个作用实际对应着后面自定义Annotation时说的@Retention三种值分别表示的Annotation
3.Annotation分类
a.标准Annotation Override, Deprecated, SuppressWarnings
标准 Annotation 是指 Java 自带的几个 Annotation,上面三个分别表示重写函数,不鼓励使用(有更好方式、使用有风险或已不在维护),忽略某项 Warning
b.元Annotation @Retention, @Target, @Inherited, @Documented
4.Annotation 自定义
1.调用
public class App{
@MethodInfo(author = "Charles",date = "2017/11/21",version = 2)
}
这里是调用自定义 Annotation——MethodInfo 的示例。
MethodInfo Annotation 作用为给方法添加相关信息,包括 author、date、version。
2.定义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo{
String author() default " ";
String date() default " ";
int version(); default 1;
}
这里是 MethodInfo 的实现部分
(1). 通过 @interface 定义,注解名即为自定义注解名
(2). 注解配置参数名为注解类的方法名,且:
a. 所有方法没有方法体,没有参数没有修饰符,实际只允许 public & abstract 修饰符,默认为 public,不允许抛异常
b. 方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组
c. 若只有一个默认属性,可直接用 value() 函数。一个属性都没有表示该 Annotation 为 Mark Annotation
(3). 可以加 default 表示默认值
3.元 Annotation 分析
@Decumented 是否保存到javadoc文档中
@Retention(RetentionPolicy.RUNTIME); 保留时长,可选SOURCE(源码时),Class(编译时),RUNTIME(运行时). 默认为CLASS,SOURCE大都为Mark Annotation 这类Annotation大都用校验,比如Override,SuppressWarnings
@Tager 可以用来修饰那些程序元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等,未标注则表示可修饰所有
@Inherited 是否可以被继承,默认是false
5.Annotation 解析
1.运行时Annotation 解析
(1)运行时Annotation 指@Retention 为RUNTIME的Annotation,可手动调用下面常用API解析:
method.getAnnotation(AnnotationName.class);
method.getAnnotations();
method.isAnnotationPresent(AnnotationName.class);
其他@Tager 如Field,Class方法类似
getAnnotation(AnnotationName.class)表示得到该Tager某个Annotation的信息,因为一个Tager可以被多个Annotation修饰
getAnnotation()则表示得到该Tager所有Annotation
isAnnotationPresent(AnnotationName.class)表示该Tager是否被某个Annotation修饰
(2)解析实列:
public static void main(String[] args) {
try {
Class cls = Class.forName("cn.trinea.java.test.annotation.App");
for (Method method : cls.getMethods()) {
MethodInfo methodInfo = method.getAnnotation(
MethodInfo.class);
if (methodInfo != null) {
System.out.println("method name:" + method.getName());
System.out.println("method author:" + methodInfo.author());
System.out.println("method version:" + methodInfo.version());
System.out.println("method date:" + methodInfo.date());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
以之前自定义的 MethodInfo 为例,利用 Target(这里是 Method)getAnnotation 函数得到 Annotation 信息,然后就可以调用 Annotation 的方法得到响应属性值
2.编译时Annotation 解析
(1)编译时Annotation指@Retention为Class的Annotation,由编译器自动解析,需要做的有一下
a. 自定义类继承自AbstractProcessor
b.重写其中的process函数
这块很多同学不理解,实际是编译器在编译时自动查找所有继承自 AbstractProcessor 的类,然后调用他们的 process 方法去处理
(2)假设MethodInfo的 @Retention 为Class,解析如下:
@SupportedAnnotationTypes({ "cn.trinea.java.test.annotation.MethodInfo" })
public class MethodInfoProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
HashMap<String, String> map = new HashMap<String, String>();
for (TypeElement te : annotations) {
for (Element element : env.getElementsAnnotatedWith(te)) {
MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
map.put(element.getEnclosingElement().toString(), methodInfo.author());
}
}
return false;
}
}
SupportedAnnotationTypes 表示这个 Processor 要处理的 Annotation 名字。
process 函数中参数 annotations 表示待处理的 Annotations,参数 env 表示当前或是之前的运行环境
process 函数返回值表示这组 annotations 是否被这个 Processor 接受,如果接受后续子的 rocessor 不会再对这个 Annotations 进行处理
网友评论