上一节中我们说了Java之中非常主要的一个实例---注解的入门,这节我们结合反射中的invoke动态调用看看注解的作用域问题
继承是Java的一个重要特性而覆写是Java继承中不可获取的,而编辑器对于覆写的地方会只能添加Override对于这些大家都是习以为常了。但是这个是必须的吗?NO……去掉Override自己手动编译Java程序的时候依然没问题,这是为什么?我们先看看啥么是Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
Java源码中这么解释:1 Override只是说明告诉开发者这个方法是被覆写啦,并未功能性的含义。还有这个是给编辑器看的也就是做idea开发人员需要开发的功能
看了这些对我们有什么用呢?这个是为了引入今天注解是有它的作用环境和作用域的引子,我们来看看上栗注解的构成
@Target 代表这个注解标注的目标(往下看可以看出这个也是个注解)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
Target自身也是个注解,它的内部返回的是个数组枚举:以此来获取这个注解实用的对象---TYPE ,FIELD,METHD ……
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
这个代表注解在Java编译运行是这个注解所处的位置和运行时怎么使用,也就是说是在源码文件中还是在编译后的文件中甚至是动态获取
综合就是---Target在代码层次确定目标目标位置 Retention面向底层确定底层怎么使用
理论一大堆,我们结合之前一块看看怎么使用
先看代码后解读
void run(@AnimalBean(animal = "com.company.Duck") Animal animal) {
System.out.println("run before");
animal.move();
System.out.println("run after");
}
这次我们把注解放置到方法的参数位置---参数注解,对应的我们需要修改我们的注解让其可以在runtime时使用,它修饰目标为方法参数
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.TYPE, ElementType.METHOD})
@interface AnimalBean {
String animal();
}
常规调用方式是new一个对象然后调用方法,但是这样我们就没法使用注解啦。那么我们怎么使用呢?其实这个时候需要的就是另一个方式invoke动态调用
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException{
…………
}
在Java的层面Class实例可以动态创建,方法可以动态绑定创建
Object strInstance = Class.forName("java.lang.String").newInstance();
Method strMethod = strInstance.getClass().getDeclaredMethod("toString");
strMethod.invoke(strInstance);
当然了这里看不到数据输出--没有赋值,那么看看如何使用这个样的特性实现我们的run方法呢?
AnimalFactory factory = new AnimalFactory();
Method method = factory.getClass().getDeclaredMethod("run", Animal.class);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
if (parameter.isAnnotationPresent(AnimalBean.class)) {
AnimalBean animalBean = parameter.getAnnotation(AnimalBean.class);
String animalName = animalBean.animal();
Animal animalObj = (Animal) Class.forName(animalName).newInstance();
Object result = method.invoke(factory, animalObj);
System.out.println(result);
}
}
我们创建了实例AnimalFactory factory = new AnimalFactory(),然后获取Class和Method和然后根据参数的注解动态创建出了Animal,最后invoke调用
Object result = method.invoke(factory, animalObj);
实现了通过注解完成参数的动态解析,当然这个是内部基本的实现逻辑思维,现实中我们不会一步步这么写,我们会采用Spring框架实现……