1. 简介
注解(也被称为元数据),为我们在代码中添加信息提供了一种形式化的方法。注解在一定程度上是把元数据与源代码文件结合在一起,而不是保存在外部文档中这一大趋势之下所催生的。
它可以提供用来完整的描述程序所需的信息,而这些信息是无法使用java来表达的。因此,注解使得我们能够以将编译器来测试和验证的格式,存储有关程序的额外信息。注解可以用来生成描述符文件,甚至是新的类定义。通过使用注解,我们可以将这些元数据保存在java源代码中,并利用annotation
api为自己的注解构造处理工具。
注解可以生成更加干净易读的代码以及编译器类型检查等等。
注解(annotation)实在实际的源代码级别保存所有的信息,而不是某种注释性文字(comment),这使得代码更加简洁,便于维护。
2. 注解分类
按照运行机制分类
描述
源码注解
注解只在源码中存在,编译成.class文件就不存在了
编译时注解
注解只在源码和.class文件中都存在(例如:@override)
运行时注解
在运行阶段还起作用,甚至影响运行逻辑的注解(例如:@autowired)
3. 内置注解:
(1)@override
表示当前的方法定义将覆盖超类中的方法。如果你不小心拼写错误,或者方法签名对不上被覆盖的方法,编译器就会发出错误提示。
(2)@deprecated
如果程序员使用了注解为它的元素,那么编译器会发出警告信息。
(3)@suppresswarnings
关闭不当的编译器警告信息(在java se5 之前,也可以使用这个注解,不过被忽略不起作用)
4. 基本语法
4.1 定义注解
可以看到注解的定义很像接口的定义。事实上,与其他任何java接口一样,注解也会被编译成class文件。
<code>package com.qunar.annotation;</code>
<code> </code>
<code>import java.lang.annotation.documented;</code>
<code>import java.lang.annotation.elementtype;</code>
<code>import java.lang.annotation.inherited;</code>
<code>import java.lang.annotation.retention;</code>
<code>import java.lang.annotation.retentionpolicy;</code>
<code>import java.lang.annotation.target;</code>
<code>public class annotation {</code>
<code>// 定义description注解</code>
<code>@target(elementtype.method)</code>
<code>@retention(retentionpolicy.runtime)</code>
<code>@inherited</code>
<code>@documented</code>
<code>// 使用@interface 关键字定义注解</code>
<code>public @interface description{</code>
<code>// 成员以无参无异常方式声明</code>
<code>string desc();</code>
<code>string author();</code>
<code>// 可以使用default关键字为成员指定一个默认值</code>
<code>int age() default 18;</code>
<code>}</code>
除了@符号以外,@description的定义很像一个接口。定义注解的时候会需要一些元注解,如@target和@retention。@target用来定义你的注解将用于什么地方(是一个方法上还是一个类上),@retention用来定义该注解在哪一个级别上可用(在源代码上或者是类文件上或者是运行时),具体下面讲解。
4.2 注解元素
注解@description中包含int元素age,以及string元素desc和author。注解元素可以使用的类型如下:
所有基本数据类型(int,float,boolean等)
string
class
enum
annotation
以上类型的数组
如果你使用了其他类型,那么编译器就会报错。注意,也不允许使用任何包装类型,不过由于自动打包的存在,这算不上什么限制。注解也可以作为元素的类型,也就是注解可以嵌套。
4.3 默认值限制
编译器对元素的默认值有些过分的挑剔。
首先,元素不能有不确定的值,也就是说元素必须要么有默认值,要么使用注解时提供元素的值。
其次,对于非基本类型的元素,无论是在源代码中声明时,或者是在注解接口中定义默认值时,都不能以null作为其值。为了这个约束,我们只能自己定义一些特殊的值,例如空字符串或者负数,来表示某个元素不存在。
4.4 元注解
元注解只负责注解其他的注解。
元注解
参数
@taget
constructor
构造器的声明
表示注解可以用于什么地方
field
域声明
method
方法声明
package
包声明
parameter
参数声明
type
类,接口或enum声明
local_variable
局部变量声明
@retention
source
表示需要在什么级别保存该注解信息
注解只会在.class文件存在,会被vm丢弃
runtime
vm将在运行期也保留注解,因此可以通过反射机制读取注解的信息
@document
将此注解包含在javadoc中
@inherited
允许子类继承父类中的注解
4.5 使用注解
语法:@<注解名称>(<成员名1> = <成员值1>,<成员名2> = <成员值2>,...)
<code>import com.qunar.annotation.annotation.description;</code>
<code>public class student {</code>
<code>private string name;</code>
<code></code>
<code>@description(desc = "set name for student object" , author = "sjf0115")</code>
<code>public string getname() {</code>
<code>return name;</code>
<code>@description(desc = "get name from student object" , author = "sjf0115", time = "2016-01-11")</code>
<code>public void setname(string name) {</code>
<code>this.name = name;</code>
5. 解析注解
通过反射机制获取类,函数或者成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。
<code>import java.lang.reflect.method;</code>
<code>public class parseannotation {</code>
<code>public static void main(string[] args){</code>
<code>class<?> class1 = null;</code>
<code>try {</code>
<code>// 使用类加载器加载类</code>
<code>class1 = class.forname("com.qunar.annotation.student");</code>
<code>} catch (classnotfoundexception e) {</code>
<code>e.printstacktrace();</code>
<code>// 判断student类上是否有description注解</code>
<code>boolean isexits = class1.isannotationpresent(description.class);</code>
<code>if(isexits){</code>
<code>// 注解实例</code>
<code>description desc = class1.getannotation(description.class);</code>
<code>system.out.println("注解:" + desc.tostring());</code>
<code>}//if</code>
<code>// 获取student类上的所有方法</code>
<code>method[] methods = class1.getmethods();</code>
<code>// 遍历所有方法</code>
<code>for (method method : methods) {</code>
<code>// 判断方法上是否有description注解</code>
<code>isexits = method.isannotationpresent(description.class);</code>
<code>description description = method.getannotation(description.class);</code>
<code>system.out.println("方法注解:" + description.tostring());</code>
<code>}//for</code>
运行结果:
方法注解:@com.qunar.annotation.annotation$description(time=2016-01-12, desc=set name for student object, author=sjf0115)
方法注解:@com.qunar.annotation.annotation$description(time=2016-01-11, desc=get name from student object, author=sjf0115)
<code>import java.lang.annotation.annotation;</code>
<code>// 方法上获取所有的注解</code>
<code>annotation[] annotations = method.getannotations();</code>
<code>for (annotation annotation : annotations) {</code>
<code>if(annotation instanceof description){</code>
<code>system.out.println("description注解:" + annotation.tostring());</code>
这两个程序都用到了反射的方法:getmethods()和getannotation(),它们都属于annotatedelement接口(class,method与field等类都实现了该接口)。getannotation()方法返回指定类型的注解对象,在这里就是description。如果被注解的方法上没有该类型的注解,则返回null值。