1 Annotation

1.1 Annotation 概念及作用

     1.  概念

  An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.[3]

  能够添加到 Java 源代码的语法元数据。类、方法、变量、参数、包都可以被注解,可用来将信息元数据与程序元素进行关联。

  更直观的理解,它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。

2.  定义    

 Annotation通过如下的方式进行定义

public @interface Override {
}

  其中的@interface是一个关键字,这个关键字声明隐含了一个信息:它是继承了java.lang.annotation.Annotation接口,并非声明了一个interface。在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字。定义的详细内容参考[1.2.3]自定义Annotation一节。

 3.  作用

  Annotation的引入是为了从Java语言层面上,为Java源代码提供元数据的支持

    (1).   标记,用于告诉编译器一些信息

    Marker Annotation:该Annotation没有参数输入,更多类似于标识一个东西,类似于Java语言中的java.io.Serialable之类的接口,并无需要实现的方法。

    (2).   编译时动态处理,如动态生成代码

    (3).   运行时动态处理,如得到注解信息

1.2  Annotation 分类

1.2.1    标准 Annotation

      1.     @Override

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

   2.     @Deprecated

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}

   3.    @SuppressWarnings

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}

  标准Annotation是指Java自带的几个Annotation,上面三个分别表示重写函数,函数已经被禁止使用,忽略某项Warning

1.2.2    元 Annotation

 元Annotation是指用来定义Annotation的Annotation

     1.   @Retention

 @Retention表示Annotation作用范围和保留时间,可选值SOURCE(源码时),CLASS(编译时),RUNTIME(运行时),默认为 CLASS,值为 SOURCE 大都为Mark   Annotation,这类Annotation 大都用来校验,比如Override, SuppressWarnings

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
public enum RetentionPolicy {
/* Annotations are to be discarded by the compiler. */
SOURCE,
/* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior. */
CLASS,
/* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
* @see java.lang.reflect.AnnotatedElement */
RUNTIME
}

   2.     @Target

  @Target 表示Annotation可以用来修饰哪些程序元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等,未标注则表示可修饰所有

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE
}

   3.     @Inherited[4][5]

  @Inherited 表示父类Annotation可以被子类继承

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

  @Inherited标识某个被标注的类型是被继承的。使用了@Inherited修饰的annotation类型被用于一个class之时,则这个annotation将被用于该class的相应子类。

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个  @Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

  就是说, 查看查找@Inherited过的Annotation之时,需要反复的向上查找,方才可以。

     4.     @Documented

  @Documented所修饰的Annotation连同自定义Annotation所修饰的元素一同保存到Javadoc文档中

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

1.2.3    自定义Annotation

  自定义Annotation表示自己根据需要定义的Annotation,定义时需要用到上面的元Annotation。这里只是一种分类而已,也可以根据作用域分为源码时、编译时、运行时 Annotation。

  下面通过自定义Annotation MethodInfo,以实例来具体介绍自定义Annotation的使用。

   1.   自定义Annotation定义

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
String author() default "trinea@gmail.com";
String date();
int version() default 1;
}

  MethodInfo Annotation定义部分:

    (1)   通过@interface 定义,注解名即为自定义注解名

    (2)   注解配置参数名为注解类的方法名,且:

      a)   所有方法没有方法体,方法名即为属性名,没有参数没有修饰符,实际只允许 public & abstract 修饰符,默认为 public ,不允许抛异常

      b)  方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组,返回类型即为属性类型

      c)  若只有一个默认属性,可直接用 value() 函数。一个属性都没有表示该 Annotation 为 Mark Annotation

      d)  可以加 default 表示默认值,null不能作为成员默认值

  2.      自定义Annotation调用

public class App {
@MethodInfo( author =“xiaotian”, date="2014/02/14", version=2)
public String getAppName() {
return "trinea";
}
}

这里是调用自定义Annotation--MethodInfo的示例,MethodInfo Annotation 作用为给方法添加相关信息,包括 author、date、version

 3.   运行时Annotation解析

    (1).   Annotation解析API

  运行时Annotation指@Retention为RUNTIME的Annotation,可手动调用下面常用 API 解析。

public interface AnnotatedElement {
/* Returns true if an annotation for the specified type
* is present on this element, else false. This method
* is designed primarily for convenient access to marker annotations.*/
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); /* Returns this element's annotation for the specified type if
* such an annotation is present, else null */
<T extends Annotation> T getAnnotation(Class<T> annotationClass); /* Returns all annotations present on this element. (Returns an array
* of length zero if this element has no annotations.) The caller of
* this method is free to modify the returned array; it will have no
* effect on the arrays returned to other callers */
Annotation[] getAnnotations(); /* Returns all annotations that are directly present on this
* element. Unlike the other methods in this interface, this method
* ignores inherited annotations. (Returns an array of length zero if
* no annotations are directly present on this element.) The caller of
* this method is free to modify the returned array; it will have no
* effect on the arrays returned to other callers */
Annotation[] getDeclaredAnnotations(); }

  其中Constructor,Field,Method都继承类class AccessibleObject implements AnnotatedElement;可通过如下接口来解析annotation:

  • element.getAnnotation(AnnotationName.class):

  表示得到element某个 AnnotationName的信息,因为一个 Target 可以被多个 Annotation 修饰

  • element.getAnnotations( ) :

  则表示得到element所有Annotations

  • element.isAnnotationPresent(AnnotationName.class):

  表示该元素是否被某个 AnnotationNam修饰

  (2).    App解析实例分析

public static void main(String[] args) {
try {
Class cls = Class.forName("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 Annotation为例,利用 Target(这里是 Method)getAnnotation函数得到Annotation信息,然后就可以调用Annotation的方法得到响应属性值

 4.      编译时Annotation解析

    (1).     编译时Annotation解析过程

  编译时Annotation指@Retention为CLASS 的Annotation,由apt(Annotation Processing Tool) 解析自动解析。

  需要做的

      a)   自定义类集成自AbstractProcessor

      b)   重写其中的 process 函数

      实际是 apt(Annotation Processing Tool) 在编译时自动查找所有继承自 AbstractProcessor 的类,然后调用他们的 process 方法去处理

    (2).     解析示例

  假设之前自定义的MethodInfo的@Retention为CLASS,

@SupportedAnnotationTypes({ " 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 进行处理。

参考

[1].    The Java™ Tutorials : http://docs.oracle.com/javase/tutorial/java/annotations/

[2].   APT: Compile-Time Annotation Processing with Java

http://www.javalobby.org/java/forums/t17876.html

[3].   Java annotation : http://en.wikipedia.org/wiki/Java_annotation

[4].     Java中@Inherited注解的运用: http://xiangdefei.iteye.com/blog/1044199

[5].   Annotation Inheritance Examples: http://www.jroller.com/alessiopace/entry/annotation_inheritance_examples

Java Annotation 机制源码分析与使用的更多相关文章

  1. ApplicationEvent事件机制源码分析

    <spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...

  2. Java split方法源码分析

    Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...

  3. Springboot学习04-默认错误页面加载机制源码分析

    Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ...

  4. 【JAVA】ThreadLocal源码分析

    ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...

  5. 【Java】HashMap源码分析——常用方法详解

    上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...

  6. 【Java】HashMap源码分析——基本概念

    在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...

  7. Android事件分发机制源码分析

    Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...

  8. 细说并发5:Java 阻塞队列源码分析(下)

    上一篇 细说并发4:Java 阻塞队列源码分析(上) 我们了解了 ArrayBlockingQueue, LinkedBlockingQueue 和 PriorityBlockingQueue,这篇文 ...

  9. Java中ArrayList源码分析

    一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...

随机推荐

  1. 异常处理:Sys.WebForms.PageRequestManagerParserErrorException:The message……

    如果你为了使页面可以达到局部刷新的效果,并且用了UpdatePanel控件,这是如果你在后台页面用到Response对象时肯呢过会抛出一下异常: 解决方法:$(document).ready(func ...

  2. wordpress主题结构_源码

    WordPress博客主题的工作机制 WordPress主题由一系列模板文件组成,每个文件分别控制主题的特定区域.无论你处于哪个页面都能看到的网站的静态部分,由header文件.sidebar和foo ...

  3. 理解MVC模式

    理解一般意义上的MVC模式 MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为以下三个基本部分: 模型(Model):模型用于封装与应用程序的业务逻 ...

  4. CE_现金账户转账汇入汇出交易(案例)(未完成)

    2014-07-15 BaoXinjian 一.摘要 二.案例   通过 Oracle Payments 结算事务处理 通过付款模板 事物处理子类型 已验证 -> 正在结算中 ->

  5. POJ 2342 &&HDU 1520 Anniversary party 树形DP 水题

    一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点) ...

  6. vim使用快捷键

    vim使用快捷键 索引 1. 关于Vim 1.1 Vim的几种模式 2. 启动Vim 3. 文档操作 4. 光标的移动 4.1 基本移动 4.2 翻屏 4.3 标记 5. 插入文本 5.1 基本插入 ...

  7. Python2.7.5 安装(转载)

    From:http://www.cnblogs.com/balaamwe/p/3480430.html From:http://www.chgon.com/?p=1340 安装python2.7.5纠 ...

  8. java虚拟机参数设置

    -Xms8000M  初始化的堆大小   -Xmx8000M  堆的最大值 -XX:+HeapDumpOnOutOfMemoryError 堆溢出时Dump出当前内存堆转储快照以便事后分析 -XX:P ...

  9. VVDocumenter-Xcode 规范注释生成器 插件之安装调试适应新版本

    1.下载地址: 很多时候,为了快速开发,很多的技术文档都是能省则省,这个时候注释就变得异常重要,再配合Doxygen这种注释自动生成文档的,就完美了.但是每次都要手动输入规范化的注释,着实也麻烦,但有 ...

  10. java从控制台读取数据的方式

    1. Scanner sc = new Scanner(System.in); String s = sc.readLine(); 2. BufferReader br = new BufferRea ...