之前在上一篇文章中介绍了Java反射机制的作用和一些用法,这篇文章作为回顾记录一下就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
@Inherited
public @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
@Inherited
public @interface IAnno {
}
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值,我们给这个自定义注解声明几个方法,也就是配置参数:
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @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);
}
}
关于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反射一般都是围绕以下方法来展开:
所以,掌握好这些方法 的用法基本是对反射的入门有所了解了