博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[03] 处理注解:反射
阅读量:4632 次
发布时间:2019-06-09

本文共 11276 字,大约阅读时间需要 37 分钟。

1、AnnotatedElement接口

如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了。使用注解的过程中,很重要的一部分就是创建于使用注解处理器。Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。
Java用Annotation接口来代表程序元素前面的注解,
该接口是所有Annotation类型的父接口。如在java.lang.reflect包中有一个接口AnnotatedElement,其中定义了一些注解相关的方法,如判断某元素是否标注了注解的方法:
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
  • 这里的传参实际上就是传入 ”某个注解.class“ 
另外,Java在java.lang.reflect 包下新增了 
AnnotatedElement 接口:
/**  * Represents an annotated element of the program currently running in this * VM.  This interface allows annotations to be read reflectively.  All * annotations returned by methods in this interface are immutable and * serializable.  It is permissible for the caller to modify the * arrays returned by accessors for array-valued enum members; it will * have no affect on the arrays returned to other callers. * * 

If an annotation returned by a method in this interface contains * (directly or indirectly) a {@link Class}-valued member referring to * a class that is not accessible in this VM, attempting to read the class * by calling the relevant Class-returning method on the returned annotation * will result in a {@link TypeNotPresentException}. * *

Similarly, attempting to read an enum-valued member will result in * a {@link EnumConstantNotPresentException} if the enum constant in the * annotation is no longer present in the enum type. * *

Finally, Attempting to read a member whose definition has evolved * incompatibly will result in a {@link * java.lang.annotation.AnnotationTypeMismatchException} or an * {@link java.lang.annotation.IncompleteAnnotationException}. * * @since 1.5 * @author Josh Bloch */

26
 
1
/**
2
* Represents an annotated element of the program currently running in this
3
* VM.  This interface allows annotations to be read reflectively.  All
4
* annotations returned by methods in this interface are immutable and
5
* serializable.  It is permissible for the caller to modify the
6
* arrays returned by accessors for array-valued enum members; it will
7
* have no affect on the arrays returned to other callers.
8
*
9
* 

If an annotation returned by a method in this interface contains

10
* (directly or indirectly) a {@link Class}-valued member referring to
11
* a class that is not accessible in this VM, attempting to read the class
12
* by calling the relevant Class-returning method on the returned annotation
13
* will result in a {@link TypeNotPresentException}.
14
*
15
* 

Similarly, attempting to read an enum-valued member will result in

16
* a {@link EnumConstantNotPresentException} if the enum constant in the
17
* annotation is no longer present in the enum type.
18
*
19
* 

Finally, Attempting to read a member whose definition has evolved

20
* incompatibly will result in a {@link
21
* java.lang.annotation.AnnotationTypeMismatchException} or an
22
* {@link java.lang.annotation.IncompleteAnnotationException}.
23
*
24
* @since 1.5
25
* @author Josh Bloch
26
*/
该接口代表程序中可以接受注解的程序元素,这句话怎么理解?我们从另一头倒着来理:
(1)Field、Method、Constructor
在反射中我们知道的像属性、方法、构造函数等封装的类,都继承了一个类,叫AccessibleObject;
(2)AccessibleObject ()
java.lang.reflect包中有类AccessibleObject,从类的注释可以看出,The AccessibleObject class is the base class for Field, Method and 
Constructor objects. It provides the ability to flag a reflected 
object as suppressing default Java language access control checks
 when it is used. 显然,它可以让一个反射对象去禁止Java语言的访问控制检测,从而能够调用对象的私有属性和方法。
这个类实现了一个接口,就是我们提到的AnnotatedElement了,
实现该接口的类(Represents an annotated element of the program currently running in this VM.  This interface allows annotations to be read reflectively.
)即代表那些可注解的元素,同时可以利用反射机制读取注解。所以,它的几个主要实现类有
  • Class  类
  • Constructor  构造器
  • Field  类的成员变量
  • Method  类的方法
  • Package  类的包
注意:如Class、Package未继承AccessibleObject,毕竟这两个类不需要所谓的访问权限设置,但是它们是实现了AnnotatedElement接口的。
所以当我们通过反射获取某个类的AnnotatedElement对象之后,就可以调用AnnotatedElement接口定义好的几个方法:
  • //判断该程序元素上是否包含指定类型的注解,存在返回true,否则返回false
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
  • //返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null
  • <T extends Annotation> T getAnnotation(Class<T> annotationClass);
  • //返回该程序元素上存在的所有注解
  • Annotation[] getAnnotations();
  • //返回直接存在于该元素上的所有注解(与该接口中其他方法不同,该方法将忽略继承的注解)
  • //如果没有注解直接存在于此元素上,则返回长度为零的一个数组
  • //该方法调用者可以随意修改返回的数组,不会对其他调用者返回的数组产生影响
  • Annotation[] getDeclaredAnnotations();

2、AnnotatedElement使用示例

2.1 自定义注解

/** * 水果名称注解 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitName {    String value() default "";}/** * 水果颜色注解 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitColor {    /**     * 颜色枚举     */    public enum Color {BULE, RED, GREEN}    /**     * 颜色属性     */    public Color fruitColor() default Color.GREEN;}/** * 水果供应商注解 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitProvider {    /**     * 供应商编号     */    public int id() default -1;    /**     * 供应商名称     */    public String name() default "";    /**     * 供应商地址     */    public String address() default "";}
54
 
1
/**
2
* 水果名称注解
3
*/
4
@Target(ElementType.FIELD)
5
@Retention(RetentionPolicy.RUNTIME)
6
@Documented
7
public @interface FruitName {
8
   String value() default "";
9
}
10
 
11
 
12
/**
13
* 水果颜色注解
14
*/
15
@Target(ElementType.FIELD)
16
@Retention(RetentionPolicy.RUNTIME)
17
@Documented
18
public @interface FruitColor {
19
   /**
20
    * 颜色枚举
21
    */
22
   public enum Color {
BULE, RED, GREEN}
23
 
24
   /**
25
    * 颜色属性
26
    */
27
   public Color fruitColor() default Color.GREEN;
28
}
29
 
30
 
31
/**
32
* 水果供应商注解
33
*/
34
@Target(ElementType.FIELD)
35
@Retention(RetentionPolicy.RUNTIME)
36
@Documented
37
public @interface FruitProvider {
38
 
39
   /**
40
    * 供应商编号
41
    */
42
   public int id() default -1;
43
 
44
   /**
45
    * 供应商名称
46
    */
47
   public String name() default "";
48
 
49
   /**
50
    * 供应商地址
51
    */
52
   public String address() default "";
53
 
54
}
注意:当一个Annotation类型被定义为运行时(RUNTIME)的Annotation时,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

2.2 使用自定义注解的类

/** * 苹果类 */public class Apple {    /**     * 苹果名称     */    @FruitName("红富士")    private String appleName;    /**     * 苹果颜色     */    @FruitColor(fruitColor = FruitColor.Color.RED)    private String appleColor;    /**     * 苹果供应商     */    @FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红富士大厦")    private String appleProvider;    public String getAppleName() {        return appleName;    }    public void setAppleName(String appleName) {        this.appleName = appleName;    }    public String getAppleColor() {        return appleColor;    }    public void setAppleColor(String appleColor) {        this.appleColor = appleColor;    }    public String getAppleProvider() {        return appleProvider;    }    public void setAppleProvider(String appleProvider) {        this.appleProvider = appleProvider;    }}
47
 
1
/**
2
* 苹果类
3
*/
4
public class Apple {
5
 
6
   /**
7
    * 苹果名称
8
    */
9
   @FruitName("红富士")
10
   private String appleName;
11
 
12
   /**
13
    * 苹果颜色
14
    */
15
   @FruitColor(fruitColor = FruitColor.Color.RED)
16
   private String appleColor;
17
 
18
   /**
19
    * 苹果供应商
20
    */
21
   @FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红富士大厦")
22
   private String appleProvider;
23
 
24
   public String getAppleName() {
25
       return appleName;
26
   }
27
 
28
   public void setAppleName(String appleName) {
29
       this.appleName = appleName;
30
   }
31
 
32
   public String getAppleColor() {
33
       return appleColor;
34
   }
35
 
36
   public void setAppleColor(String appleColor) {
37
       this.appleColor = appleColor;
38
   }
39
 
40
   public String getAppleProvider() {
41
       return appleProvider;
42
   }
43
 
44
   public void setAppleProvider(String appleProvider) {
45
       this.appleProvider = appleProvider;
46
   }
47
}

2.3 注解处理

public class FruitInfoUtil {    /**     * 获取水果信息     * @param clazz 类对象     */    public static void getFruitInfo(Class
clazz) { String strFruitName; String strFruitColor; String strFruitProvider; //获取该类对象包含的所有属性对象 Field[] fields = clazz.getDeclaredFields(); //遍历属性对象 for (Field field : fields) { //如果属性包含的注解是FruitName if (field.isAnnotationPresent(FruitName.class)) { FruitName fruitName = field.getAnnotation(FruitName.class); strFruitName = "水果名称:" + fruitName.value(); System.out.println(strFruitName); } //如果属性包含的注解是FruitColor else if (field.isAnnotationPresent(FruitColor.class)) { FruitColor fruitColor = field.getAnnotation(FruitColor.class); strFruitColor = "水果颜色:" + fruitColor.fruitColor().toString(); System.out.println(strFruitColor); } //如果属性包含的注解是FruitProvider else if (field.isAnnotationPresent(FruitProvider.class)) { FruitProvider fruitProvider = field.getAnnotation(FruitProvider.class); strFruitProvider = "供应商编号:" + fruitProvider.id() + ";供应商名称:" + fruitProvider.name() + ";供应商地址:" + fruitProvider.address(); System.out.println(strFruitProvider); } } } }
41
 
1
public class FruitInfoUtil {
2
 
3
   /**
4
    * 获取水果信息
5
    * @param clazz 类对象
6
    */
7
   public static void getFruitInfo(Class
clazz) {
8
 
9
       String strFruitName;
10
       String strFruitColor;
11
       String strFruitProvider;
12
 
13
       //获取该类对象包含的所有属性对象
14
       Field[] fields = clazz.getDeclaredFields();
15
 
16
       //遍历属性对象
17
       for (Field field : fields) {
18
           //如果属性包含的注解是FruitName
19
           if (field.isAnnotationPresent(FruitName.class)) {
20
               FruitName fruitName = field.getAnnotation(FruitName.class);
21
               strFruitName = "水果名称:" + fruitName.value();
22
               System.out.println(strFruitName);
23
           }
24
           //如果属性包含的注解是FruitColor
25
           else if (field.isAnnotationPresent(FruitColor.class)) {
26
               FruitColor fruitColor = field.getAnnotation(FruitColor.class);
27
               strFruitColor = "水果颜色:" + fruitColor.fruitColor().toString();
28
               System.out.println(strFruitColor);
29
           }
30
           //如果属性包含的注解是FruitProvider
31
           else if (field.isAnnotationPresent(FruitProvider.class)) {
32
               FruitProvider fruitProvider = field.getAnnotation(FruitProvider.class);
33
               strFruitProvider = "供应商编号:" + fruitProvider.id()
34
                       + ";供应商名称:" + fruitProvider.name()
35
                       + ";供应商地址:" + fruitProvider.address();
36
               System.out.println(strFruitProvider);
37
           }
38
       }
39
   }
40
   
41
}

2.4 测试和结果输出

public class TestAnnotation {    public static void main(String[] args) {        FruitInfoUtil.getFruitInfo(Apple.class);    }}//结果输出水果名称:红富士水果颜色:RED供应商编号:1;供应商名称:陕西红富士集团;供应商地址:陕西省西安市延安路89号红富士大厦
x
 
1
public class TestAnnotation {
2
   public static void main(String[] args) {
3
       FruitInfoUtil.getFruitInfo(Apple.class);
4
   }
5
}
6
 
7
//结果输出
8
水果名称:红富士
9
水果颜色:RED
10
供应商编号:1;供应商名称:陕西红富士集团;供应商地址:陕西省西安市延安路89号红富士大厦

3、参考链接

转载于:https://www.cnblogs.com/deng-cc/p/7462588.html

你可能感兴趣的文章
mysql中 where in 用法
查看>>
Farseer.net轻量级开源框架 中级篇:探究ORM(Mapping)
查看>>
对象,对象引用变量理解
查看>>
14Oracle Database 高级事务,游标
查看>>
Qt无法调试Qvector
查看>>
小白_Unity引擎_MonoBehaver
查看>>
图论算法——SPFA算法
查看>>
linux实现自动检测进程是否存活的脚本
查看>>
HttpWatch的时间分析
查看>>
CSS3 Transform
查看>>
loadrunner生成随机数
查看>>
LoadRunner测试场景中添加负载生成器
查看>>
20145315 《信息安全系统设计基础》第9周学习总结
查看>>
windows系统下安装memcache
查看>>
20170502 匹配单个字符串
查看>>
day7
查看>>
实战 iTextSharp
查看>>
C语言学习及应用笔记之七:C语言中的回调函数及使用方式
查看>>
四则运算2 设计思路
查看>>
c#之线程池优先级
查看>>