上面的一篇博客我们讲到了注解的定义。但是,光有注解定义是不能够满足我们编程的需要的,我们还要给注解加上事件。注解和事件的关系,举一个例子,就是我们平时写的网页,网页中写的html就是我们的java代码,代码中的 id,class 属性就是我们的注解,目的是表明一个特定的标签(java中可能是类,函数,属性等)。而我们可以在js中通过id,class找到这样的一个标签,给标签添加上一系列的事件。
而类似‘给标签添加上事件’,在java中的描述则是,给有annotation的对象通过反射添加上一定的事件或内容。下面不扯了,直接上一个例子:
package yue.keyuan;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Order {
int value() default 1;
}
class AnnotatedClass {
@Order(value = 1)
public void one() {
System.out.println("这是第一个函数");
}
@Order(value = 3)
public void three() {
System.out.println("这是第三个函数");
}
@Order(value = 2)
public void two() {
System.out.println("这是第二个函数");
}
public void four() {
System.out.println("这是第四个函数");
}
}
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class<AnnotatedClass> object = AnnotatedClass.class;
// 通过反射获取AnnotatedClass 实例
AnnotatedClass instance = object.newInstance();
// 获取所有的方法
Method[] methods = object.getDeclaredMethods();
// 这里定义TreeMap 放置method,以便有排序
Map<Integer, Method> methodMap = new TreeMap<Integer, Method>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.intValue() - o2.intValue();
}
});
// 获取含有@Order注解的函数
for (Method method : methods) {
if (method.isAnnotationPresent(Order.class)) {
Order annotation = method.getAnnotation(Order.class);
methodMap.put(annotation.value(), method);
}
}
// 按顺序执行方法
methodMap.forEach((key, value) -> {
try {
value.invoke(instance);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
代码运行的结果是:
这是第一个函数
这是第二个函数
这是第三个函数
我们可以看出,不管我们函数的定义顺序如何,代码完全是按照我们在 @Order中定义的顺序执行的。而 four()这一个函数却没有被执行,也是因为我们没有添加注解。
在我们的Main类的main函数中,正式我们通过反射的方法调用含有注解的函数的过程。关于反射的具体内容,这里简单的介绍反射的几个函数或类。
首先是Class类,这个就是代表我们的一个类的具体的信息。我们可以同个则个类来获取任何我们想要知道的关于这个类的信息。而生成这样的一个类,我们可以调用任何一个类的 .class属性获得,或者 Class.forName(String className); 调用获得。
- newInstance() 函数表示我们通过这样的一个Class来生成一个实例化的一个类,
- Class 类的getMethod, getAnnotation, getField 等类可以帮助我们获取这个类中具体的方法,注解,字段等内容。
Method 类代表的是一个类中的具体的一个函数,这个函数可以是任何类型的。
- 通过Method 的 getAnnotations, getAnnotationByType 等函数我们可以获取这样的一个Method 的注解。
- Method可以通过具体的它中间的invoke 方法调用,invoke中间要放上具体的实例,后后面可以接上具体的参数值。
其他的一些类和Class 和Method 类似,这里就不多做描述。
下面再举一个例子,我们模仿一下 Junit 这个库来做一系列的封装。上代码:
package yue.security;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Junit {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Before {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface test {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface After {
}
@Junit
class AnnotatedClass {
private int step = 0;
@Before
public void init() {
System.out.println("init");
System.out.println(step++);
}
@test
public void test1() {
System.out.println("test1");
System.out.println(step++);
}
@test
public void test2() {
System.out.println("test2");
System.out.println(step++);
}
@After
public void close() {
System.out.println("close");
System.out.println(step);
}
}
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 获取反射的 Class
Class<AnnotatedClass> object = AnnotatedClass.class;
// 通过反射获取AnnotatedClass 实例
AnnotatedClass instance = object.newInstance();
// 获取所有的方法
Method[] methods = object.getDeclaredMethods();
// 执行初始化的方法
for (Method method : methods) {
if (method.isAnnotationPresent(Before.class)) {
method.invoke(instance);
}
}
// 执行test 方法
for (Method method : methods) {
if (method.isAnnotationPresent(test.class)) {
method.invoke(instance);
}
}
// 执行 after 方法扫尾
for (Method method : methods) {
if (method.isAnnotationPresent(After.class)) {
method.invoke(instance);
}
}
}
}
这个类执行后的结果是:
init
0
test1
1
test2
2
close
3