浅谈Java反射与Annotation
程序员文章站
2024-01-20 17:29:28
...
通过Java反射机制,编程人员可以更加深入的控制程序的运行过程。从JDK1.5开始新增了Annotation功能,本文主要讲述Java反射的相关内容,包括定义Annotation类型的方法和在程序运行时访问Annotation信息的方法。通过学习本文,你能构了解到:通过反射访问构造方法的的方法、访问成员变量的方法、访问方法的方法、定义Annotation类型的方法、访问Annotation信息的方法。
- Class类与Java反射
package annotation.blog;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BlogDemoReflect {
public static void main(String[] args) {
BlogDemo bd = new BlogDemo("test");
Class bdC = bd.getClass();
// 包路径
Package packageUrl = bdC.getPackage();
System.out.println(packageUrl);
// 类名称
String className = bdC.getName();
System.out.println(className);
// 继承类
Class classObj = bdC.getSuperclass();
System.out.println(classObj);
// 实现接口
Class[] interfaceObjs = bdC.getInterfaces();
// 权限为public构造方法
Constructor[] constructors = bdC.getConstructors();
// 所有构造方法
Constructor[] allConstructors = bdC.getDeclaredConstructors();
// 权限为public方法
Method[] methods = bdC.getMethods();
// 所有方法
Method[] allMethods = bdC.getDeclaredMethods();
// 权限为public的成员变量
Field[] fields = bdC.getFields();
// 所有成员变量
Field[] allFields = bdC.getDeclaredFields();
}
}
注意:getFields()和getMethod()获得权限为public的成员变量和方法,包含从超类中继承得到的成员变量和方法;通过getDeclaredFields()和getDeclaredMethods()只是获得本类中的所有成员和方法。执行具有可变数量的参数的构造方法时,需要将入口参数定义为二维数组。- 使用Annotation功能
package annotation.blog;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
String value() default "test";
}
定义一个Annotation需要使用接口的关键字interface,需要在其前方加上@符号,该关键字的隐含意思为继承了java.lang.annotation.Annotation接口。@Target用来设置Annotation类型适用的程序元素种类,未设置默认是所有程序元素。枚举类ElementType中的枚举常量用来设置@Target:
ANNOTATION_TYPE:表示用于Annotation类型;
TYPE:表示用于类、接口和枚举,以及Annotation类型;
CONSTRUCTOR:用于构造方法;
FIELD:用于成员变量和枚举常量;
METHOD:用于方法;
PARAMETER:用于参数;
LOCAL_VARIABLE:用于局部变量;
PACKAGE:用于包;
@Retention可以设置Annotation的有效范围。枚举类RetentionPolicy中的枚举常量设置@Retention:
SOURCE:不编译Annotation到类文件中,有效范围小;
SOURCE:不编译Annotation到类文件中,有效范围小;
CLASS:编译Annotation到类文件中,但运行时不加载Annotation到JVM中;
RUNTIME:表示运行时加载Annotation到JVM中,有效范围最大。
访问Annotation信息:
如果在定义Annotation类型时将@Retention设置为RetentionPolicy.RUNTIME,运行程序时通过反射就可以获取到相关的Annotation信息,如构造方法、字段、方法的Annotation信息。以Retry注解为实例进行分析:
注解类:
package annotation.retry;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
int interval() default 3;
int time() default 4000;
}
注解处理器类:package annotation.retry;
import java.lang.reflect.Method;
class MyRunnable implements Runnable{
private int interval;
private int time;
private Method method;
public MyRunnable(int interval, int time, Method method){
this.interval = interval;
this.time = time;
this.method = method;
}
@Override
public void run() {
for(int i = 0; i < interval; i++){
try {
method.invoke(new Object(), "Hello World");
Thread.sleep(time);
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class RetryProcessor {
public void parseMethod(Class<?> clazz) throws Exception{
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods){
Retry retry = method.getAnnotation(Retry.class);
if(retry != null){
int interval = retry.interval();
int time = retry.time();
System.out.println(interval);
System.out.println(time);
Thread t = new Thread(new MyRunnable(interval, time, method));
t.start();
}
}
}
}
注解测试类:package annotation.retry;
public class RetryTest {
@Retry
public static void sayHello(String name){
System.out.println("say hello1 " + name);
}
@Retry(interval = 9, time = 9000)
public static void sayHello2(String name){
System.out.println("say hello2 " + name);
}
public static void main(String[] args) throws Exception {
RetryProcessor retry = new RetryProcessor();
retry.parseMethod(RetryTest.class);
}
}
- 总结
上一篇: DOM事件-调用函数