摘要:注解的定義注解通過關鍵字進行定義它的形式跟接口很類似,不過前面多了一個符號上面的代碼就創建了一個名字為的注解你可以簡單理解為創建了一張名字為的標簽注解的應用上面創建了一個注解那么注解的的使用方法是什么呢創建一個類然后在類定義的地方加上就可以
java jdk: 10.0.2注解的定義
注解通過 @interface 關鍵字進行定義.
public @interface TestAnnotation { }
它的形式跟接口很類似,不過前面多了一個 @ 符號. 上面的代碼就創建了一個名字為 TestAnnotaion 的注解.
你可以簡單理解為創建了一張名字為 TestAnnotation 的標簽.
注解的應用上面創建了一個注解, 那么注解的的使用方法是什么呢.
@TestAnnotation public class Test { }
創建一個類 Test, 然后在類定義的地方加上 @TestAnnotation 就可以用 TestAnnotation 注解這個類了.
你可以簡單理解為將 TestAnnotation 這張標簽貼到 Test 這個類上面.
不過, 要想注解能夠正常工作, 還需要介紹一下一個新的概念那就是元注解.
元注解元注解是什么意思呢?
元注解是可以注解到注解上的注解, 或者說元注解是一種基本注解, 但是它能夠應用到其它的注解上面.
如果難于理解的話, 你可以這樣理解. 元注解也是一張標簽, 但是它是一張特殊的標簽, 它的作用和目的就是給其他普通的標簽進行解釋說明的.
元標簽有 @Retention、 @Documented、@Target、 @Inherited、 @Repeatable 5 種.
@RetentionRetention 的英文意為保留期的意思. 當 @Retention 應用到一個注解上的時候, 它解釋說明了這個注解的的存活時間.
它的取值如下:
RetentionPolicy.SOURCE 注解只在源碼階段保留, 在編譯器進行編譯時它將被丟棄忽視.
RetentionPolicy.CLASS 注解只被保留到編譯進行的時候, 它并不會被加載到 JVM 中.
RetentionPolicy.RUNTIME 注解可以保留到程序運行的時候, 它會被加載進入到 JVM 中, 所以在程序運行時可以獲取到它們.
我們可以這樣的方式來加深理解, @Retention 去給一張標簽解釋的時候, 它指定了這張標簽張貼的時間.
@Retention 相當于給一張標簽上面蓋了一張時間戳, 時間戳指明了標簽張貼的時間周期.
@Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { }
上面的代碼中, 我們指定 TestAnnotation 可以在程序運行周期被獲取到, 因此它的生命周期非常的長.
@Documented顧名思義, 這個元注解肯定是和文檔有關. 它的作用是能夠將注解中的元素包含到 Javadoc 中去.
@TargetTarget 是目標的意思, @Target 指定了注解運用的地方.
你可以這樣理解, 當一個注解被 @Target 注解時, 這個注解就被限定了運用的場景.
ElementType.ANNOTATION_TYPE 可以給一個注解進行注解
ElementType.CONSTRUCTOR 可以給構造方法進行注解
ElementType.FIELD 可以給屬性(字段)進行注解
ElementType.LOCAL_VARIABLE 可以給局部變量進行注解
ElementType.METHOD 可以給方法進行注解
ElementType.PACKAGE 可以給一個包進行注解
ElementType.PARAMETER 可以給一個方法內的參數進行注解
ElementType.TYPE 可以給一個類型進行注解, 比如類、接口、枚舉
@InheritedInherited 是繼承的意思, 但是它并不是說注解本身可以繼承, 而是說如果一個超類被 @Inherited 注解過的注解進行注解的話, 那么如果它的子類沒有被任何注解應用的話, 那么這個子類就繼承了超類的注解.
說的比較抽象. 代碼來解釋.
@Inherited @Retention(RetentionPolicy.RUNTIME) @interface Test {} @Test public class A {} public class B extends A {}
注解 Test 被 @Inherited 修飾, 之后類 A 被 Test 注解, 類 B 繼承 A, 類 B 也擁有 Test 這個注解.
@RepeatableRepeatable 自然是可重復的意思.
什么樣的注解會多次應用呢? 通常是注解的值可以同時取多個.
舉個例子, 一個人他既是程序員又是產品經理, 同時他還是個畫家.
@interface Persons { Person[] value(); } @Repeatable(Persons.class) @interface Person{ String role default ""; } @Person(role="artist") @Person(role="coder") @Person(role="PM") public class SuperMan{ }
注意上面的代碼, @Repeatable 注解了 Person. 而 @Repeatable 后面括號中的類相當于一個容器注解.
什么是容器注解呢? 就是用來存放其它注解的地方. 它本身也是一個注解.
我們再看看代碼中的相關容器注解.
@interface Persons { Person[] value(); }
按照規定, 它里面必須要有一個 value 的屬性, 屬性類型是一個被 @Repeatable 注解過的注解數組, 注意它是數組.
注解的屬性@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { int id(); String msg(); }
上面代碼定義了 TestAnnotation 這個注解中擁有 id 和 msg 兩個屬性. 在使用的時候, 我們應該給它們進行賦值.
賦值的方式是在注解的括號內以 value=”” 形式, 多個屬性之前用 , 隔開.
@TestAnnotation(id=3,msg="hello annotation") public class Test { }
?? 在注解中定義屬性時它的類型必須是 8 種基本數據類型外加 類、接口、注解及它們的數組.判斷類上是否使用指定注解
Map判斷字段上是否使用指定注解> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) ->{ ReflectionClass annotation = value.getAnnotation(ReflectionClass.class); if (annotation != null) { System.out.println("class name: " + value.getSimpleName() + ", 注解 value : " + annotation.Value()); } });
Map判斷方法上是否使用指定注解> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) -> { for (Field declaredField : ClassUtil.getAnnotatedDeclaredFields(value, ReflectionField.class, false)) { ReflectionField annotation = declaredField.getAnnotation(ReflectionField.class); if (annotation != null) { this.put(annotation.Value(), declaredField); System.out.println("class name: " + value.getSimpleName() + ", 字段名: " + declaredField.getName() + ", 字段類型:" + declaredField.getType().getSimpleName() + ", 注解值:" + annotation.Value() ); } } });
Map創建對象> stringClassMap = ClassUtil.getClasses("org.itzhizhe.testReflection"); stringClassMap.forEach((key, value) -> { for (Method declaredField : ClassUtil.getAnnotatedDeclaredMethods(value, ReflectionMethod.class,false)) { ReflectionMethod annotation = declaredField.getAnnotation(ReflectionMethod.class); if (annotation != null) { System.out.println("class name: " + value.getSimpleName() + ", 方法名: " + declaredField.getName() + ", 方法返回類型:" + declaredField.getReturnType() + ", 注解值:" + annotation.id() ); } } });
value.getConstructor().newInstance();
上面代碼是使用無參構造來創建對象, 當然也可以使用有參構造來創建對象.
getConstructor() 參數填寫構造參數的參數類型.
newInstance() 參數填寫傳給構造參數的值.
調用方法可以通過 Method 的 setAccessible 方法設置為 true, 就可以調用對象的 private 方法.
declaredField.setAccessible(true); declaredField.invoke(value);
然后可以使用 invoke 方法來進行方法調用. 第一個參數為要調用方法的對象. 剩下的參數是方法參數.
總結如果想實現像 Spring 這種框架, 實現上面幾步是必須.
比如依賴注入, 我們需要知道字段的類型, 然后到 IOC 容器中找到對應的對象進行賦值.
而方法調用你可以先將注解的方法進行保存, 比如保存到 Map 集合中.
例如客戶端發送指定數據幀后, 然后通過 key 取出要執行的方法后執行就可以.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72326.html
摘要:反射機制一結合官方通過編寫的反射教程,復習一下反射的知識。反射的概念反射是一種在運行時獲取以及修改應用行為的一種工具。因為反射需要動態的解析類的信息,相比于非反射使用的方式要慢。反射需要獲取一定的運行時權限,在特定的安全環境下不一定存在。 Java反射機制(一) 結合Oracle官方通過JDK8編寫的反射教程,復習一下反射的知識。結尾篇補一個小例子。 主要內容 這次博客的主要內容就是簡...
摘要:通過反射獲取帶參無返回值成員方法并使用設置安全檢查,訪問私有構造函數必須創建實例這種不行,注意和方法需要傳遞參數測試復制這個功能獲取私有方法,同樣注意和的區別賦予訪問權限調用方法。 反射 目錄介紹 1.反射概述 1.1 反射概述 1.2 獲取class文件對象的三種方式 1.3 反射常用的方法介紹 1.4 反射的定義 1.5 反射的組成 1.6 反射的作用有哪些 2.反射的...
摘要:反射使用類對象提供的基本元數據,能從類對象中找出方法或字段的名稱,然后獲取表示方法或字段的對象。常見的反射手段有反射和反射。以之前的反射為例其中指定了方法的返回類型,其實不止如此。 Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類 在運行時構造任意一個類的對象 在運行時判斷任意一個類所具有的成員變量和方法 在運行時調用任意一個對象的方法 生成動態代理 很多框架...
近期在維護公司項目的時候遇到一個問題,因為實體類中的 set 方法涉及到了業務邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實現功能,所以采用了反射的機制給對象屬性賦值,借此機會也了解了反射的一些具體用法和使用場景,分以下兩點對反射進行分析: 反射的優勢和劣勢 反射的應用場景 反射的優勢和劣勢 ??個人理解,反射機制實際上就是上帝模式,如果說方法的調用是 Java 正確的打開方式...
摘要:一反射機制概念程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言,如,是動態語言顯然,,不是動態語言,但是有著一個非常突出的動態相關機制。相關的為二獲取源頭重點打開權限所有類的對象其實都是的實例。 一、Java反射機制概念 程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言,如Python, Ruby是動態語言;顯然C++,Java,C#不是動態語言,但是JAVA有...
閱讀 1762·2021-11-24 09:39
閱讀 1551·2021-11-16 11:54
閱讀 3497·2021-11-11 16:55
閱讀 1655·2021-10-14 09:43
閱讀 1445·2019-08-30 15:55
閱讀 1232·2019-08-30 15:54
閱讀 3420·2019-08-30 15:53
閱讀 1337·2019-08-30 14:18