Java注解和反射

来源:互联网 发布:黄光裕入狱知乎 编辑:程序博客网 时间:2024/04/25 07:56

之前在上一篇文章中介绍了Java反射机制的作用和一些用法,这篇文章作为回顾记录一下就Java的注解和反射一起使用的例子:

1. Java的注解

首先来看一个例子

package com.yd.annotationstest;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.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface IAnno {    String stringValue();    int intValue();}
package com.yd.annotationstest;public class AnnoClass {    @IAnno(stringValue = "test-integer-value", intValue = 9)    public String str;    @IAnno(intValue = 3, stringValue = "test-string-value")    public int inte;    @IAnno(stringValue = "method01",intValue = -1)    public void method01(){        System.out.println("this is method01");    }    @IAnno(stringValue = "method02",intValue = -6)    public void method02(String str, int intValue){        System.out.println("this is method01 and str = " + str +", intValue = "+ intValue);    }}

在AnnoClass里的属性和方法上面出现了
@IAnno(stringValue = “test-integer-value”, intValue = 9)

这些东西,可能第一次看,大部分人并不知道这是啥东西,代表什么意思,有什么作用,有些人可能会联想到在Java类中子类重写父类方法时,在方法上面会自动出现一个@Override字样,告诉我这个是重写父类的方法,没错,这个就是注解,它起着说明,标注的作用,那么总的来说,注解有以下几个作用:

1.生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等;
2.跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量;
3.在编译时进行格式检查。如@Override放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出;

上面的
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
有什么具体作用呢,往下看:

@Target,@Retention,@Documented,@Inherited,这四个是注解的元注解,元注解是java API提供,是专门用来定义注解的注解,其作用分别如下:

@Target 表示该注解的作用域,可以用的地方,它值在枚举类 ElemenetType 中,包括:
ElemenetType.CONSTRUCTOR —————————————构造器声明
ElemenetType.FIELD —————————————————域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE ————————————局部变量声明
ElemenetType.METHOD ———————————————方法声明
ElemenetType.PACKAGE ———————————————包声明
ElemenetType.PARAMETER ——————————————参数声明
ElemenetType.TYPE —————————————————类,接口(包括注解类型)或enum声明

@Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:
RetentionPolicy.SOURCE ———————————注解将被编译器丢弃
RetentionPolicy.CLASS ———————————–注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM——-将在运行期也保留注释,因此可以通过反射机制读取注解的信息。

@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。

@Inherited 允许子类继承父类中的注解。

上面的AnnoClass类中声明的元注解是其标准写法,要自定义一个注解写法必须是@interface + 注解名称:
如:

public @interface zhujie {}public @interface anno {}

上面写上元注解
如:

@Target({ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface IAnno {}

@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值,我们给这个自定义注解声明几个方法,也就是配置参数:

@Target({ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface IAnno {String stringValue() default "";int intValue() default 0;Class gid();}

如果定义的注解里面只有一个配置参数,可命名为value,加上返回类型,如

@Documented@Target(METHOD)@Retention(RUNTIME)public @interface POST {  String value() default "";}

AnnoClass 类,给属性和方法加上定义好的注解:

package com.yd.annotationstest;public class AnnoClass {    // 注:定义的注解里只有一个配置参数,可写成@IAnno("est-string-value")    // 或者@IAnno(9)    @IAnno(stringValue = "test-integer-value", intValue = 9)    public String str;    @IAnno(intValue = 3, stringValue = "test-string-value")    public int inte;    @IAnno(stringValue = "method01",intValue = -1)    public void method01(){        System.out.println("this is method01");    }    @IAnno(stringValue = "method02",intValue = -6)    public void method02(String str, int intValue){        System.out.println("this is method01 and str = " + str +", intValue = "+ intValue);    }}

2. Java反射

关于Java反射网上有很多文章都有介绍,如果还不清楚,请参考我的上一篇文章JavaReflect(Java反射机制) ,这里不多做介绍,后面将结合上面注解的例子来写几个Java反射常用的方法。

package com.yd.annotationstest;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public class Main {    /**     * @param args     */    public static void main(String[] args) {        Class<?> fClass;        try {            // 实例化Class            fClass = Class.forName("com.yd.annotationstest.AnnoClass");            System.out.println("*********line01*********");            // 获取定义的属性            Field field[] = fClass.getFields();            for (int i = 0; i < field.length; i++) {                System.out.println("修饰符: "+Modifier.toString(field[i].getModifiers())+"  属性名: "+ field[i].getName());                // 获取属性的注解                Annotation[] annotations = field[i].getAnnotations();                for (Annotation a : annotations) {                    IAnno ian = (IAnno) a;                    System.out.println("注解:  intValue: " + ian.intValue() + "  stringValue: " + ian.stringValue());                }            }            System.out.println("*********line02*********");            // 获取所有方法            Method[] method = fClass.getMethods();            for (int i = 0; i < method.length; i++) {                System.out.println(Modifier.toString(method[i].getModifiers()) +"  "+ method[i].getName());                // 获取方法的注解                Annotation[] annotations = method[i].getAnnotations();                for (Annotation a : annotations) {                    IAnno ian = (IAnno) a;                    System.out.println("注解:  intValue: " + ian.intValue() + "  stringValue: " + ian.stringValue());                }            }            System.out.println("*********line03*********");            // 通过反射对方法传值赋值            Method mth = fClass.getMethod("method02", String.class, int.class);            mth.invoke(fClass.newInstance(), "hehhe", 100);            System.out.println("*********line04*********");            // 通过反射对属性赋值            Object obj = fClass.newInstance();            // 获取属性            Field fld = fClass.getDeclaredField("str");            fld.setAccessible(true);            // 赋值            fld.set(obj, "test-invoke");            System.out.println(fld.get(obj));        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (SecurityException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (NoSuchFieldException e) {            e.printStackTrace();        }    }}

输出结果:

****line01****
修饰符: public 属性名: str
注解: intValue: 9 stringValue: test-integer-value
修饰符: public 属性名: inte
注解: intValue: 3 stringValue: test-string-value
****line02****
public method02
注解: intValue: -6 stringValue: method02
public method01
注解: intValue: -1 stringValue: method01
public final wait
public final wait
public final native wait
public native hashCode
public final native getClass
public equals
public toString
public final native notify
public final native notifyAll
****line03****
this is method01 and str = hehhe, intValue = 100
****line04****
test-invoke

上面的例子,通过反射获取AnnoClass中的属性、方法,并给属性赋值、方法传值,实现反射基本的用法。
可以看出,Java反射一般都是围绕以下方法来展开:

  • java.lang.Class;
  • java.lang.reflect.Constructor; java.lang.reflect.Field; 类属性
  • java.lang.reflect.Method; 类方法
  • java.lang.reflect.Modifier; 修饰符
  • getDeclaredMethods() 获取所有声明的方法
  • getReturnType() 获得方法的放回类型
  • getParameterTypes() 获得方法的传入参数类型
  • getDeclaredMethod(“方法名”,参数类型.class,……) 获得特定的方法
  • getDeclaredField(); 获得特定的属性
  • getDeclaredConstructors() 获取所有的构造方法
  • getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法
  • getSuperclass() 获取某类的父类
  • getInterfaces() 获取某类实现的接口
  • getAnnotations()获取类所有注解
  • invoke()请求执行
    ……

所以,掌握好这些方法 的用法基本是对反射的入门有所了解了

原创粉丝点击