java注解学习(2)

上面的一篇博客我们讲到了注解的定义。但是,光有注解定义是不能够满足我们编程的需要的,我们还要给注解加上事件。注解和事件的关系,举一个例子,就是我们平时写的网页,网页中写的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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值