Java之invoke与方法参数注解
- 2019 年 10 月 4 日
- 筆記
上一节中我们说了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框架实现……