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框架實現……