1.Annotation是什么?
注解是JDK5新增的,主要为程序增加元数据。Annotation是一种接 口,主要用来对JAVA应用程序元素设置元数据。需要通过JAVA反射技术获得Annotation对象,根据Annotation对象实例获取程序元素上的元数据信息即Annotation信息。
2.如何定义Annotation?
定义注解Annotation很简单,通过关键字@interface即可定义一个注解。下图自定义一个注解。
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
// 作者
String author() default "tonny";
// 日期
String date();
}
3.哪些程序元素可以使用注解?
JAVA应用中哪些程序元素可以使用Annotation。在JDK中另外一个AnnotatedElement接口代表了程序中可以使用Annotation的程序元素,JDK中具体的实现类主要有:
3.1 Class:JAVA类从面可以使用注解Annotation.
3.2. Constructor:构造器可以使用注解Annotation。
3.3. Method:JAVA类中的方法可以使用注解Annotation
3.4. Field:JAVA类中的成员变量可以使用Annotation,Spring中 很多场景。
3.5. Package: 类的包定义上使用注解
4.注解特点
4.1.注解中可以定义方法,但都是无参的方法,即不能有任何参数。
4.2.注解中的方法可以有默认值,必须使用default 赋值。上述中,就是采用default进行赋值
4.3.注解中的方法名和返回类型就是注解中的成员变量名和变量类型
4.4.注解的返回类型只能是基本类型,String,枚举类型,Annotation类型和这些类型组成的数组–非常重要
4.5.注解中如果定义成员变量,如果成员变量没有默认值(即没有使用default进行赋值),则在使用该注解时必须对成员变量进行赋值。
4.6.注解中可以包含元注解,元注解被用来定义自定义注解
5.四个元注解
JDK中提供了4个元数据注解,这4个元注解可以注解自定义注解
5.1@Target:
5.1.1.主要表明使用@Target注解的范围,可以在哪些应用程序元素中使用。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
5.1.2.@Target的注解范围通过ElementType枚举类数组指定:
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
}
5.1.3.上述程序中是元注释@Target源码,可以发现@target包含元注解,通过该ElementType.ANNOTATION_TYPE指明了注解的范围。
5.1.4.@Target注解的方法名为value,即成员变量名。返回类型为一个枚举ElementType。符合注解中方法的返回类型要求(枚举类型或枚举类型数组)
5.1.5.通常情况下使用注解中的方法时,应该使用”name=value”形式。即 上述程序中@Target(ElementType.ANNOTATION_TYPE)
应该为@Target(value = ElementType.ANNOTATION_TYPE)。如下情况特殊除外:
5.1.5.1如果自定义的注解中就含有一个成员变量而且成员变量的名称为value,则可以不需要使用name=value形式。
5.2@Retention
5.2.1使用@Retention修饰自定义的Annotation,表明该Annotation的声明周期
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
5.2.2上述源码表明@Retention生命周期通过RetentionPolicy控制。RetentionPolicy为枚举类,主要包含3个数值:
5.2.2.1.RetentionPolicy.SOURCE:编译器直接丢弃这种策略。
5.2.2.2.RetentionPolicy.CLASS:编译器将Annotation记录在CLASS文件中,但是JVM在运行时会抛弃。这也是默认行为
5.2.2.3RetentionPolicy的源码如下:
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
}
5.3@Inherited
5.3.1@Inherited指定被它注解的Annotation将具有继承性质,如果某 个类使用了自定义注解A(A注解被@Inherited修饰),则A的子类也具有A注解的特性。
5.3.2@Inherited的源码如下,只是标记注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
5.4@Documented
5.4.1.@Documented修饰的注解可以被javadoc工具文档化。也是一个标记注解,源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
6.自定义注解
6.1自定义注解只需要使用@interface声明即可,如下定义了MethodInfo注解
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
// 作者
String author() default "tonny";
// 日期
String date();
// 版本
int version() default 1;
// 注释
String comments();
}
6.2.定义了AnnotationExample类,使用自定义注解,如下
public class AnnotationExample {
@Override
@MethodInfo(author="tonny",date="2016-08-11",comments="override toString method")
public String toString(){
return "Override toString method";
}
@Deprecated
@MethodInfo(date="2016-08-11",comments="deprecated method")
public void oldMethod(){
System.out.println("deprecated method do not use it");
}
@SuppressWarnings(value = { "unchecked" })
@MethodInfo(date="2016-08-11",comments="deprecated method")
public List generateList(){
List l = new ArrayList();
l.add("a");
l.add("b");
return l;
}
}
6.3.类AnnotationParse.java是一个简单的解析注解的小程序:
public class AnnotationParse {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Method[] methods = AnnotationParse.class.getClassLoader()
.loadClass("com.egfbank.annotaion.example1.AnnotationExample")
.getMethods();
for(Method m:methods){
// getAnnotations()返回指定元素上所有的注释
for(Annotation anno : m.getAnnotations()){
System.out.println("annotation : "+anno);
}
//检查 注解MethodInfo是否起到作用
// 判断程序中指定元素上某个特定的注释是否存在
if(m.isAnnotationPresent(MethodInfo.class)){
MethodInfo ma = m.getAnnotation(MethodInfo.class);
System.out.println(ma.author());
System.out.println(ma.date());
}
}
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
7.总结
7.1通过上述例子,可以看出注解必须和反射技术结合起来才能发挥重要的作用。灵活使用注解可以减少很多无用的代码的编写。