Java注解(Annotation)详解(三)——解析注解

转: http://blog.csdn.net/zen99t/article/details/49512411

(三)解析注解

1. 注解处理器

        何为解析注解?即通过反射获取类、函数或成员上的 运行时注解信息,从而实现动态控制程序运行的逻辑。
解析注解主要用到两个类库:
1.1.  java.lang.annotation.Annotation
Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。
1.2. java.lang.reflect.AnnotatedElement
AnnotatedElement 接口代表程序中可以接受注解的程序元素,是所有程序元素(Class、Method 、Field、Package和Constructor)的父接口。获取该接口对象之后,即可以调用对象方法来访问Annotation信息,常用有如下几个:
         1. getAnnotations():返回该程序元素上存在的所有注解。
         2. isAnnotationPresent(annotation.class):判断该程序元素上是否包含指定类型的注解
         3. getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。

2. 解析注解的代码例子

定义一个注解如下:
  1. package jtzeng;  
  2. import java.lang.annotation.Documented;  
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Inherited;  
  5. import java.lang.annotation.Retention;  
  6. import java.lang.annotation.RetentionPolicy;  
  7. import java.lang.annotation.Target;  
  8. @Target({ElementType.METHOD,ElementType.TYPE})  
  9. @Retention(RetentionPolicy.RUNTIME)  
  10. @Inherited  
  11. @Documented  
  12. public @interface Description {   
  13.     String desc();  
  14.     String author() default “JTZeng”;  
  15.     int age() default 21;  
  16. }   
package jtzeng;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description { 
    String desc();
    String author() default "JTZeng";
    int age() default 21;
} 
定义一个使用了注解的Test类:
  1. package jtzeng;  
  2. @Description(desc=“this is ElementType.TYPE”,author=“JTZeng”,age=21)  
  3. public class Test1 {  
  4.     @Description(desc=“this is ElementType.METHOD”,author=“JTZeng”,age=18)  
  5.     public void run(){  
  6.         System.out.println(”I can run!”);  
  7.     }  
  8. }  
package jtzeng;
@Description(desc="this is ElementType.TYPE",author="JTZeng",age=21)
public class Test1 {
    @Description(desc="this is ElementType.METHOD",author="JTZeng",age=18)
    public void run(){
        System.out.println("I can run!");
    }
}
再编写一个解析类:
  1. package jtzeng;  
  2. import java.lang.annotation.Annotation;  
  3. import java.lang.reflect.Method;  
  4. public class ParseAnno {  
  5.     public static void main(String[] args) {  
  6.         try {  
  7.             /* 
  8.              * 1.使用类加载器加载类 
  9.              * Class.forName(“类名字符串”) (注意:类名字符串必须是全称,包名+类名) 
  10.              */  
  11.             Class c = Class.forName(”jtzeng.Test1”);  
  12.               
  13.             //2.判断类上是否存在注解,并获取类上面注解的实例  
  14.             if(c.isAnnotationPresent(Description.class)){  
  15.                 Description Description = (Description) c.getAnnotation(Description.class);  
  16.                 System.out.println(Description.desc());  
  17.                 System.out.println(Description.author());  
  18.                 System.out.println(Description.age());  
  19.             }  
  20.               
  21.             //3.判断方法上是否存在注解,并获取方法上面注解的实例  
  22.             Method[] ms = c.getMethods();  
  23.             for (Method method : ms) {  
  24.                 if(method.isAnnotationPresent(Description.class)){  
  25.                     Description Description = (Description)method.getAnnotation(Description.class);  
  26.                     System.out.println(Description.desc());  
  27.                     System.out.println(Description.author());  
  28.                     System.out.println(Description.age());  
  29.                 }  
  30.             }  
  31.             //另一种获取方法上的注解的解析方法  
  32.             for (Method method : ms) {  
  33.                 Annotation[] as = method.getAnnotations();  
  34.                 for (Annotation annotation : as) {  
  35.                     if(annotation instanceof Description){  
  36.                         System.out.println(((Description) annotation).desc());  
  37.                         System.out.println(((Description) annotation).author());  
  38.                         System.out.println(((Description) annotation).age());  
  39.                     }  
  40.                 }  
  41.             }  
  42.               
  43.         } catch (ClassNotFoundException e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.     }  
  47. }  
package jtzeng;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class ParseAnno {
    public static void main(String[] args) {
        try {
            /*
             * 1.使用类加载器加载类
             * Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名)
             */
            Class c = Class.forName("jtzeng.Test1");

            //2.判断类上是否存在注解,并获取类上面注解的实例
            if(c.isAnnotationPresent(Description.class)){
                Description Description = (Description) c.getAnnotation(Description.class);
                System.out.println(Description.desc());
                System.out.println(Description.author());
                System.out.println(Description.age());
            }

            //3.判断方法上是否存在注解,并获取方法上面注解的实例
            Method[] ms = c.getMethods();
            for (Method method : ms) {
                if(method.isAnnotationPresent(Description.class)){
                    Description Description = (Description)method.getAnnotation(Description.class);
                    System.out.println(Description.desc());
                    System.out.println(Description.author());
                    System.out.println(Description.age());
                }
            }
            //另一种获取方法上的注解的解析方法
            for (Method method : ms) {
                Annotation[] as = method.getAnnotations();
                for (Annotation annotation : as) {
                    if(annotation instanceof Description){
                        System.out.println(((Description) annotation).desc());
                        System.out.println(((Description) annotation).author());
                        System.out.println(((Description) annotation).age());
                    }
                }
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
运行解析类,结果如下,有三部分,第一部分是类上的注解,第二、三部分是不同的方法解析方法上的注解:


3.测试元注解@Retention

如果把@Retention改为SOURCE或者CLASS,再次运行ParseAnno类:

          运行结果如下,什么也没有,这进一步说明了,只有设置为RUNTIME,才可以在运行时通过反射机制来获取注解信息,从而实现动态控制程序运行的逻辑。


4. 测试元注解@Inherited

创建一个接口和一个父类,并改写Test1类:
  1. package jtzeng;  
  2. @Description(desc = “this is Interface”)    //因为注解Description中的author和age成员有默认值,所以可以省略  
  3. public interface Invalid {  
  4.     @Description(desc = “this is Interface method”)  
  5.     public void print();  
  6. }  
  7.   
  8.   
  9. package jtzeng;  
  10. @Description(desc = “this is class”)  
  11. public class Valid {  
  12.     @Description(desc = “this is class method”)  
  13.     public void run(){  
  14.         System.out.println(”注解继承只能在子类中有效,不能在接口中继承”);  
  15.     }  
  16. }  
  17.   
  18.   
  19. package jtzeng;  
  20. public class Test1 extends Valid implements Invalid {  
  21.     @Override  
  22.     public void run(){  
  23.         System.out.println(”覆盖父类的方法”);  
  24.     }  
  25.     @Override  
  26.     public void print() {  
  27.         System.out.println(”实现接口的方法”);  
  28.     }  
  29. }  
package jtzeng;
@Description(desc = "this is Interface")    //因为注解Description中的author和age成员有默认值,所以可以省略
public interface Invalid {
    @Description(desc = "this is Interface method")
    public void print();
}


package jtzeng;
@Description(desc = "this is class")
public class Valid {
    @Description(desc = "this is class method")
    public void run(){
        System.out.println("注解继承只能在子类中有效,不能在接口中继承");
    }
}


package jtzeng;
public class Test1 extends Valid implements Invalid {
    @Override
    public void run(){
        System.out.println("覆盖父类的方法");
    }
    @Override
    public void print() {
        System.out.println("实现接口的方法");
    }
}
再一次运行ParseAnno解析类,输出结果如下,说明只能继承父类的注解,并且是类上的注解:


5. 知识导图

最后给出一张Java注解的知识导图,觉得总结得不错,这里就直接拿来了,导图来源:http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值