Annotation英文单词翻译过来就是注释注解的意思,实际上它干的活也确实如此.我们在使用IDE时经常会看见一些@return,@param等样子的注释,实际上它就是一种annotation.这里估计大家都有一个共识,就是无论annotation怎么使用,它都不会改变程序最终的运行结果,这就是annotaion的特性了.那么annotation具体有什么作用呢?我们又该来怎么使用它呢?
也许大家会注意到,过时的方法往往会带有一条删除线,比如
  new Date().toLocaleString();
又或者我们写的一个类如以下片段:
@Override
 public String toString(){ return null; }
 @Override
 public void overrideTest(){ }
实际上,这时IDE会报错或者警告,但实际上这个类拿去编译,甚至运行都会毫无问题.但是它如何知道就错了呢?这就归功于Annotation注解了.编译器此时通过反射来获取这个方法的Annotation,通过Annotation来确认这个方法究竟是干嘛用的.比如注释是Override,那么它就会继续去检查父类是否有这个方法可以让子类来重写.如果没有,那么开发环境就报错.
实际上还有很多类似的用法,生成doc文档就是最常见的用法之一.那么对Annotation有了初步的了解后我们接下来就可以介绍一下Annotation了.

Annotation的作用域
SOURCE代表的是这个Annotation类型的信息只会保留在程序源码里,源码如果经过了编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里面。
ClASS的意思是这个Annotation类型的信息保留在程序源码里,同时也会保留在编译好的.class文件里面,在执行的时候,并不会把这一些信息加载到虚拟机(JVM)中去.注意一下,当你没有设定一个Annotation类型的Retention值时,系统默认值是CLASS.
RUNTIME,表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去的.
以上三个范围都是在RetentionPolicy枚举中定义好的.
public enum RetentionPolicy {
 SOURCE,
 CLASS,
 RUNTIME
}
但是我们具体申明的时候不是直接使用这个枚举,因为是注释申明,所以只能使用注释的方式,所以jdk又把这个枚举封装成了一个注释@Retention,这个注释源码如下
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
 RetentionPolicy value();
}
那,这里可以看到, Annotation可以自己给自己定义使用的,有点奇怪吧…

Annotation的运作范围
  一个annotation不是想在哪用就在哪用的,就好比java中方法必须写到类里面一样,annotation也有自己的定义范围,规定一个annotation在哪些地方可以去使用他.具体的范围有如下几个:
TYPE,
FIELD,
METHOD
PARAMETER
CONSTRUCTOR
LOCAL_VARIABLE
ANNOTATION_TYPE
PACKAGE
这几个名字不言而喻,type:申明的类型,field:字段, method:方法...等等,这里就不一一解释
好无疑问,这里jdk同样包装好了,用的是以一个ElementType枚举类型
public enum ElementType {
 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
 LOCAL_VARIABLE, ANNOTATION_TYPE,PACKAGE
}
为了annotation使用有包装了一个名为Target的annotation类型.源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
 ElementType[] value();
}
上面都找到两种annotation都提及一个@Documented,@Documented的目的就是让这一个Annotation类型的信息能够显示在javaAPI说明文档上;没有添加的话,使用javadoc生成API文档的时候就会找不到这一个类型生成的信息.

JDK5自带的几个Annotation:
@Deprecated用于修饰已经过时的方法;
@Override用于修饰此方法覆盖了父类的方法(而非重载);
@SuppressWarnings用于通知java编译器禁止特定的编译警告。

以下介绍关于Annotation的用法语法及使用了:
1。类型声明方式:
通常,应用程序并不是必须定义annotation类型,但是定义annotation类型并非难事。Annotation类型声明于一般的接口声明极为类似,区别只在于它在interface关键字前面使用“@”符号。
annotation类型的每个方法声明定义了一个annotation类型成员,但方法声明不必有参数或者异常声明;方法返回值的类型被限制在以下的范围:primitives、String、Class、enums、annotation和前面类型的数组;方法可以有默认值。

下面是一个简单的annotation类型声明:
清单1:
    /**
     * Describes the Request-For-Enhancement(RFE) that led
     * to the presence of the annotated API element.
     */
    public @interface RequestForEnhancement {
        int    id();
        String synopsis();
        String engineer() default "[unassigned]";
        String date();    default "[unimplemented]";
    }

代码中只定义了一个annotation类型RequestForEnhancement。

annotation到底能起什么作用呢?
1,    编译工具或其他工具可以根据被附加在代码里的annotation信息自动生成配置文件或文档等外部文件。
比如,sun公司就提供了apt(Annotation Processing Tool)工具,apt工具是一个可以处理annotation的命令行工具,apt提供了在编译期针对源代码级别的解析,并可以在解析时生成新的源代码和其他文件,同时还可以对生成的源代码进行编译。
2,    其他程序可以在运行时动态解析将要被执行的程序里的annotation信息,并根据被附加的annotation信息来执行不同的操作。
比如,EJB3规范就比较广泛地使用了annotation特性。比如只要在POJO为class注明@Stateless注释,EJB容器便会根据此annotation把该POJO注册为无状态的Session Bean。EJB3使用了annotation大大地简化了EJB的开发和配置过程。我们会在其他文章里专门介绍EJB Annotation的原理与使用方法,这里不做详述。

本文通过一个简单地例子来说明怎么在运行期动态解析annotation。Apt工具的使用我们会在近期其他文章里对其加以介绍。

比如,我们定义了MyAnnotation3注释:
 MyAnnotation3.java

package com.test.annotation;

import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @ interface MyAnnotation3 {
     public String value();
     public String[] multiValues();
     int number() default 0;
}

上面定义了一个名为MyAnnotation3的注释。

我们再定义一个GetMyAnnotation类,该类使用了MyAnnotation3注释:
GetMyAnnotation.java:

package com.test.annotation.test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javax.ejb.EJB;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.test.annotation.MyAnnotation3;

// 为GetMyAnnotation类附加MyAnnotation3 注释
@MyAnnotation3(value = " Class GetMyAnnotation", multiValues = {" 1"," 2"})
public class GetMyAnnotation {
     // 为testField1属性附加MyAnnotation3 注释
    @MyAnnotation3(value = " call testField1", multiValues={" 1"}, number = 1)
     private String testField1;

// 为testMethod1方法附加MyAnnotation3 注释
    @MyAnnotation3(value = " call testMethod1", multiValues={" 1", " 2"}, number = 1)
     public void testMethod1() {

}

@Deprecated
    @MyAnnotation3(value = " call testMethod2", multiValues={" 3", " 4", " 5"})
     public void testMethod2() {

}
}

上面的例子GetMyAnnotation非常简单,里面没有任何功能,但是分别为类(class),属性(field),方法(method)申明(附加)了MyAnnotation3 注释。

下面我们用程序TestMyAnnotation3对GetMyAnnotation里MyAnnotation3注释进行解析。

运行时解析annotation
TestMyAnnotation3.java

public class TestMyAnnotation3 {

public static void main(String[] args) {
        System.out.println(" --Class Annotations--");
         if (GetMyAnnotation.class.isAnnotationPresent(MyAnnotation3. class)) {
            System.out.println(" [GetMyAnnotation].annotation:");
            MyAnnotation3 classAnnotation = GetMyAnnotation.class.getAnnotation(MyAnnotation3. class);
            printMyAnnotation3(classAnnotation);
        }
        
        
        System.out.println(" --Fields Annotations--");
        Field [] fields = GetMyAnnotation.class.getDeclaredFields();
         for (Field field : fields) {
             if (field.isAnnotationPresent(MyAnnotation3. class)) {
                System.out.println(" [GetMyAnnotation." + field.getName() + " ].annotation:");
                MyAnnotation3 fieldAnnotation = field.getAnnotation(MyAnnotation3. class);
                printMyAnnotation3(fieldAnnotation);
            }
        }
        
        System.out.println(" --Methods Annotations--");
        Method[] methods = GetMyAnnotation.class.getDeclaredMethods();
         for (Method method : methods) {
            System.out.println(" [GetMyAnnotation." + method.getName() + " ].annotation:");
             if (method.isAnnotationPresent(MyAnnotation3. class)) {
                MyAnnotation3 methodAnnotation = method.getAnnotation(MyAnnotation3. class);
                printMyAnnotation3(methodAnnotation);  
            }
        }
    }
    
     private static void printMyAnnotation3(MyAnnotation3 annotation3) {
         if (annotation3 == null) {
            return;
        }
        
        System.out.println(" {value=" + annotation3.value());
        
        String multiValues = "";
         for (String value: annotation3.multiValues()) {
            multiValues += " ," + value;
        }
        
        System.out.println(" multiValues=" + multiValues);
        
        System.out.println(" number=" + annotation3.number() + " }");
    }
}

输出:

--Class Annotations--
[GetMyAnnotation].annotation:
{value=Class GetMyAnnotation
multiValues=,1,2
number=0}
--Fields Annotations--
[GetMyAnnotation.testField1].annotation:
{value=call testField1
multiValues=,1
number=1}
--Methods Annotations--
[GetMyAnnotation.testMethod1].annotation:
{value=call testMethod1
multiValues=,1,2
number=1}
[GetMyAnnotation.testMethod2].annotation:
{value=call testMethod2
multiValues=,3,4,5
number=0}

JDK1.5以后的版本提供的跟annotation有关的接口:

interface java.lang.reflect.AnnotatedElement {
     boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
    Annotation[] getAnnotations();
    Annotation[] getDeclaredAnnotations();
}

该接口主要用来取得附加在类(class),构造方法(constructor),属性(field),方法(method),包(package)上的annotation信息。

JDK1.5与此有关的几个类都实现了AnnotatedElement接口:

java.lang.reflect.AccessibleObject,
java.lang.reflect.Class,
java.lang.reflect.Constructor,
java.lang.reflect.Field,
java.lang.reflect.Method,
java.lang.reflect.Package

所以可以利用反射(reflection)功能在程序里动态解析附加的annotation信息。

总结:
本文通过举例简单地说明了怎么动态解析annotation,大家可以举一反三,利用Java的annotation特性,完成更复杂功能等。

Annotation 介绍相关推荐

  1. Annotation介绍

    Annotation思维导图

  2. Android Support Annotation介绍

    在浏览Butter Knife源码时,发现里面用了好几个support包里的注解,比如@UiThread:当时一脸懵逼,第一次见到.再学习过后,今天,介绍下support包的注解.注解可以简化代码并提 ...

  3. Annotation基础知识

    1.Annotation介绍 Annontation是Java5开始引入的新特征.中文名称一般叫注解. Annontation像一种修饰符一样,应用于包.类型.构造方法.方法.成员变量.参数及本地变量 ...

  4. Introduction of Annotation

    Annotation介绍 概念 注解Annotation是java 1.5的新特性,是一种能够添加到 Java 源代码的语法元数据.类.方法.变量.参数.包都可以被注解,可用来将信息元数据与程序元素进 ...

  5. Proguard 部分类不混淆的技巧

    Proguard 部分类不混淆的技巧 最近比较忙,博客和 codeKK 都两个月没怎么更新了.赶在月末分享个小技巧. 一.场景 两年前在 Proguard 语法及常用 proguard.cfg 代码  ...

  6. java 计算器 junit测试_Java Junit测试

    使用junit做测试目的是尽量早的发现程序的bug,一个bug隐藏的时间越久,修复他的代价就越大. 1.Junit简介: Junit最初是由Erich Gamma 和 Kent Beck 编写的一个回 ...

  7. java学习笔记第三部分

    接口 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来. interface 接口名{//属性//方法(1. 抽象方法 2.默认实现方法 3.静态方法) ...

  8. 韩顺平 2021零基础学Java 学习笔记(2)(自用)

    目录 第 10 章 面向对象编程(高级部分) 第 11 章 枚举和注解 第 12 章 异常-Exception 第 13 章 常用类 第 10 章 面向对象编程(高级部分) 10.1 类变量和类方法 ...

  9. 精通移动App测试实战:技术、工具和案例

    本文是根据书籍<精通移动App测试实战:技术.工具和案例>进行学习记录,方便后期查阅,感谢书籍作者提供的学习机会. 目录 第1章 Android系统基础内容介绍 1.6创建模拟器 第2章J ...

最新文章

  1. mysql 1061原因_MySQL死锁问题分析及解决方法实例详解(转)
  2. Google Deepmind大神David Silver带你认识强化学习
  3. snmp在企业网中的简单应用
  4. python oracle 运维,mysql oracle python连接
  5. Kalman Filter 学习笔记
  6. 【Verilog HDL学习之路】第一章 Verilog HDL 数字设计总论
  7. 1-5 线性表元素的区间删除 (20 分)
  8. 训练日志 2019.1.14
  9. 消暑圣品!这部宝马“鬼片”你看过没,第一个被无人驾驶车辆吓跑的女鬼?...
  10. python 面向对象_Python 和 Java 基础对比 08 —— 面向对象
  11. 应届生还是研究生?与大学生的MSN谈话二
  12. power bi 雷达图_【自助式数据分析平台——WonderBI(豌豆BI)】免费在线试用_软件库...
  13. 决策树和基于决策树的集成方法(DT,RF,GBDT,XGB)复习总结
  14. [USB 设备检测_1]-使用 H2testw 1.4 或其她工具检测新买的朗科 U 盘读写速度及是否是扩容盘
  15. 随机森林随机回归预测_随机森林回归预测电子商务销售额
  16. 互联网快讯:粉笔科技布局线下打造双核驱动;极米产品获用户青睐;迅雷发布2021年财报;荣耀Magic4系列国内发布
  17. 江苏高考新方案定了!总分750分,科目“3+1+2”
  18. 概率论复习笔记2.0
  19. 让View具有减速效果的动画——FlingAnimation
  20. ubuntu 文件恢复

热门文章

  1. The Thirteenth Of Word-Day
  2. java高级面试题(易错题)
  3. HttpClient 连接超时重试处理
  4. 递归算法及经典递归实现
  5. 什么是J2EE、Java SE、Java EE、Java ME?
  6. Loadrunner12.55windows-linux-os安装详细教程
  7. C语言sort和qsort函数的用法
  8. 递归算法时间复杂度分析
  9. Android横向滑动加载更多的控件的实现---HorizontalScrollSlideView
  10. sun 公司的java 认证