JAVA基礎(chǔ)之注解與反射的使用方法和場景
注解
注解定義
Java 注解(Annotation)又稱 Java 標注,是 JDK5.0 引入的一種注釋機制。
Java 語言中的類、方法、變量、參數(shù)和包等都可以被標注。和注釋不同,Java 標注可以通過反射獲取標注內(nèi)容。在編譯器生成類文件時,標注可以被嵌入到字節(jié)碼中。Java 虛擬機可以保留標注內(nèi)容,在運行 時可以獲取到標注內(nèi)容 。 當然它也支持自定義 Java 標注。
注解與注釋的區(qū)別:注解是給機器看的注釋,而注釋是給程序員看的提示,編譯時自動忽略注釋。
使用場景
編譯格式檢查
反射中解析
生成幫助文檔
跟蹤代碼依賴
等
內(nèi)置注解
注解類型 | 注解意義 | 補充說明 |
---|---|---|
@Override | 重寫 | 定義在java.lang.Override |
@Deprecated | 廢棄 | 定義在java.lang.Deprecated |
@SafeVarargs | 忽略任何使用參數(shù)為泛型變量的方法或構(gòu)造函數(shù)調(diào)用產(chǎn)生的警告 | Java 7 開始支持 |
@FunctionalInterface | 函數(shù)式接口 | Java 8 開始支持,標識一個匿名函數(shù)或函數(shù)式接口。 |
@Repeatable | 標識某注解可以在同一個聲明上使用多次 | Java 8 開始支持,標識某注解可以在同一個聲明上使用多次。 |
@SuppressWarnings | 抑制編譯時的警告信息。 | 定義在java.lang.SuppressWarnings |
*補充: @SuppressWarnings 的三種方法:
- @SuppressWarnings(“unchecked”) [^ 抑制單類型的警告]
- @SuppressWarnings(“unchecked”,“rawtypes”) [^ 抑制多類型的警告]
- @SuppressWarnings(“all”) [^ 抑制所有類型的警告]
元注解
定義:
作用在其他注解的注解
元注解類型:
注解類型 | 注解意義 |
---|---|
@Retention | 標識這個注解怎么保存,是只在代碼中,還是編入class文件中,或者是在運行時可以通過反射訪問。 |
@Documented | 標記這些注解是否包含在用戶文檔中 javadoc |
@Target | 標記這個注解應該是哪種 Java 成員 |
@Inherited | 標記這個注解是自動繼承的 |
*Inherited 補充:
- 子類會繼承父類使用的注解中被@Inherited修飾的注解
- 接口繼承關(guān)系中,子接口不會繼承父接口中的任何注解,不管父接口中使用的注解有沒有 被@Inherited修飾
- 類實現(xiàn)接口時不會繼承任何接口中定義的注解
自定義注解框架:
- Annotation 與 RetentionPolicy 與 ElementType 。
每 1 個 Annotation 對象,都會有唯一的 RetentionPolicy 屬性;至于 ElementType 屬性,則有 1~n個。 - ElementType(注解的用途類型)“每 1 個 Annotation” 都與 “1~n 個 ElementType” 關(guān)聯(lián)。當 Annotation 與某個 ElementType 關(guān)聯(lián) 時,就意味著: Annotation有了某種用途。例如,若一個 Annotation 對象是 METHOD 類型,則該 Annotation 只能用來修飾方法。
package java.lang.annotation; public enum ElementType { TYPE, /* 類、接口(包括注釋類型)或枚舉聲明 */ FIELD, /* 字段聲明(包括枚舉常量) */ METHOD, /* 方法聲明 */ PARAMETER, /* 參數(shù)聲明 */ CONSTRUCTOR, /* 構(gòu)造方法聲明 */ LOCAL_VARIABLE, /* 局部變量聲明 */ ANNOTATION_TYPE, /* 注釋類型聲明 */ PACKAGE /* 包聲明 */ }
RetentionPolicy(注解作用域策略)
“每 1 個 Annotation” 都與 “1 個 RetentionPolicy” 關(guān)聯(lián)。
a) 若 Annotation 的類型為 SOURCE,則意味著:Annotation 僅存在于編譯器處理期間,編譯器 處理完之后,該 Annotation 就沒用了。 例如," @Override" 標志就是一個 Annotation。當它修 飾一個方法的時候,就意味著該方法覆蓋父類的方法;并且在編譯期間會進行語法檢查,編譯器處理完后,"@Override" 就沒有任何作用了。
b) 若 Annotation 的類型為 CLASS,則意味著:編譯器將 Annotation 存儲于類對應的 .class 文件 中,它是 Annotation 的默認行為。
c) 若 Annotation 的類型為 RUNTIME,則意味著:編譯器將 Annotation 存儲于 class 文件中,并 且可由JVM讀入。
package java.lang.annotation; public enum RetentionPolicy { SOURCE, /* Annotation信息僅存在于編譯器處理期間,編譯器處理完之后就沒有該 Annotation信息了 */ CLASS, /* 編譯器將Annotation存儲于類對應的.class文件中。默認行為 */ RUNTIME /* 編譯器將Annotation存儲于class文件中,并且可由JVM讀入 */ }
定義格式
@interface 自定義注解名{}
2.5.3、注意事項
- 定義的注解,自動繼承了java.lang,annotation.Annotation接口
- 注解中的每一個方法,實際是聲明的注解配置參數(shù)
方法的名稱就是 配置參數(shù)的名稱
方法的返回值類型,就是配置參數(shù)的類型。只能是:基本類型/Class/String/enum - 可以通過default來聲明參數(shù)的默認值
- 如果只有一個參數(shù)成員,一般參數(shù)名為value
- 注解元素必須要有值,我們定義注解元素時,經(jīng)常使用空字符串、0作為默認值。
反射
JAVA反射機制是在運行狀態(tài)中,獲取任意一個類的結(jié)構(gòu) , 創(chuàng)建對象 , 得到方法,執(zhí)行方法 , 屬性;
這種在運行狀態(tài)動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能被稱為java語言的反射機制。
類加載器
Java類加載器(Java Classloader)是Java運行時環(huán)境(Java Runtime Environment)的一部分,
負責動態(tài)加載Java類到Java虛擬機的內(nèi)存空間中。
java默認有三種類加載器,BootstrapClassLoader、ExtensionClassLoader、App ClassLoader。
- BootstrapClassLoader(引導啟動類加載器):嵌在JVM內(nèi)核中的加載器,該加載器是用C++語言寫的,主要負載加載JAVA_HOME/lib下的類庫,引導啟動類加載器無法被應用程序直接使用。ExtensionClassLoader(擴展類加載器):
- ExtensionClassLoader是用JAVA編寫,且它的父類加載器是Bootstrap。是由sun.misc.Launcher$ExtClassLoader實現(xiàn)的,主要加載JAVA_HOME/lib/ext目錄中的類 庫。它的父加載器是BootstrapClassLoaderApp ClassLoader(應用類加載器):
- App ClassLoader是應用程序類加載器,負責加載應用程序classpath目錄下的所有jar和class文 件。它的父加載器為Ext ClassLoader
類通常是按需加載,即第一次使用該類時才加載。由于有了類加載器,Java運行時系統(tǒng)不需要知道文件與 文件系統(tǒng)。學習類加載器時,掌握Java的委派概念很重要。
雙親委派模型:
如果一個類加載器收到了一個類加載請求,它不會自己去嘗試加載這個類,而是把這個請求 轉(zhuǎn)交給父類加載器去完成。每一個層次的類加載器都是如此。因此所有的類加載請求都應該傳遞到最頂層的 啟動類加載器中,只有到父類加載器反饋自己無法完成這個加載請求(在它的搜索范圍沒有找到這個類) 時,子類加載器才會嘗試自己去加載。委派的好處就是避免有些類被重復加載。
加載配置文件
給項目添加resource root目錄
通過類加載器加載資源文件
默認加載的是src路徑下的文件,但是當項目存在resource root目錄時,就變?yōu)榱思虞d resource root下的文件了。
反射獲取Class
要想了解一個類,必須先要獲取到該類的字節(jié)碼文件對象. 在Java中,每一個字節(jié)碼文件,被夾在到內(nèi)存后,都存在一個對應的Class類型的對象
得到Class
- 如果在編寫代碼時, 知道類的名稱, 且類已經(jīng)存在, 可以通過
包名.類名.class 得到一個類的 類對象如果擁有類的對象, 可以通過 - Class 對象.getClass() 得到一個類的 類對象如果在編寫代碼時, 知道類的名稱 , 可以通過
- Class.forName(包名+類名): 得到一個類的 類對象
上述的三種方式, 在調(diào)用時, 如果類在內(nèi)存中不存在, 則會加載到內(nèi)存。如果類已經(jīng)在內(nèi)存中存在, 不會重復加載, 而是重復利用
特殊的類對象
基本數(shù)據(jù)類型的類對象:
基本數(shù)據(jù)類型.clss
包裝類.type
基本數(shù)據(jù)類型包裝類對象:
包裝類.class
反射獲取 Constructor
通過class對象 獲取一個類的構(gòu)造方法
1. 通過指定的參數(shù)類型, 獲取指定的單個構(gòu)造方法 getConstructor(參數(shù)類型的class對象數(shù)組) 例如: 構(gòu)造方法如下: Person(String name,int age) 得到這個構(gòu)造方法的代碼如下: Constructor c = p.getClass().getConstructor(String.class,int.class); 2. 獲取構(gòu)造方法數(shù)組 getConstructors(); 3. 獲取所有權(quán)限的單個構(gòu)造方法 getDeclaredConstructor(參數(shù)類型的class對象數(shù)組) 4. 獲取所有權(quán)限的構(gòu)造方法數(shù)組 getDeclaredConstructors();
Constructor 創(chuàng)建對象
newInstance(Object... para) 調(diào)用這個構(gòu)造方法, 把對應的對象創(chuàng)建出來 參數(shù): 是一個Object類型可變參數(shù), 傳遞的參數(shù)順序 必須匹配構(gòu)造方法中形式參數(shù)列表的順序 setAccessible(boolean flag) 如果flag為true 則表示忽略訪問權(quán)限檢查 !(可以訪問任何權(quán)限的方法)
反射獲取 Method
通過class對象 獲取一個類的方法
1. getMethod(String methodName , class.. clss) 根據(jù)參數(shù)列表的類型和方法名, 得到一個方法(public修飾的) 2. getMethods(); 得到一個類的所有方法 (public修飾的) 3. getDeclaredMethod(String methodName , class.. clss) 根據(jù)參數(shù)列表的類型和方法名, 得到一個方法(除繼承以外所有的:包含私有, 共有, 保護, 默認) 4. getDeclaredMethods(); 得到一個類的所有方法 (除繼承以外所有的:包含私有, 共有, 保護, 默認)
Method 執(zhí)行方法
invoke(Object o,Object... para) : 調(diào)用方法 , 參數(shù)1. 要調(diào)用方法的對象 參數(shù)2. 要傳遞的參數(shù)列表 getName() 獲取方法的方法名稱 setAccessible(boolean flag) 如果flag為true 則表示忽略訪問權(quán)限檢查 (可以訪問任何權(quán)限的方法)
反射獲取 Field
通過class對象 獲取一個類的屬性
1. getDeclaredField(String filedName) 根據(jù)屬性的名稱, 獲取一個屬性對象 (所有屬性) 2. getDeclaredFields() 獲取所有屬性 3. getField(String filedName) 根據(jù)屬性的名稱, 獲取一個屬性對象 (public屬性) 4. getFields() 獲取所有屬性 (public)
Field 屬性的對象類型
常用方法: 1.. get(Object o); 參數(shù): 要獲取屬性的對象 獲取指定對象的此屬性值 2. set(Object o , Object value); 參數(shù)1. 要設(shè)置屬性值的 對象 參數(shù)2. 要設(shè)置的值 設(shè)置指定對象的屬性的值 3. getName(); 獲取屬性的名稱 4. setAccessible(boolean flag); 如果flag為true 則表示忽略訪問權(quán)限檢查 !(可以訪問任何權(quán)限的屬性)
通過反射獲取注解信息
獲取類/屬性/方法的全部注解對象
Annotation[] annotations01 = Class/Field/Method.getAnnotations(); for (Annotation annotation : annotations01) { System.out.println(annotation); }
根據(jù)類型獲取類/屬性/方法的注解對象
注解類型 對象名 = (注解類型) c.getAnnotation(注解類型.class);
內(nèi)省 Introspector
基于反射 , java所提供的一套應用到JavaBean的API
Bean類:
一個定義在包中的類 ,
擁有無參構(gòu)造器
所有屬性私有,
所有屬性提供get/set方法
實現(xiàn)了序列化接口
Java提供了一套java.beans包的api , 對于反射的操作, 進行了封裝
獲取Bean類信息
方法:
BeanInfo getBeanInfo(Class cls) 通過傳入的類信息, 得到這個Bean類的封裝對象 .
獲取bean類的 get/set方法 數(shù)組
常用的方法: MethodDescriptor[] getPropertyDescriptors():
MethodDescriptor
常用方法:
1. Method getReadMethod(); 獲取一個get方法 2. Method getWriteMethod(); 獲取一個set方法
有可能返回null 注意 需要加判斷
總結(jié)
到此這篇關(guān)于JAVA基礎(chǔ)之注解與反射的使用方法和場景的文章就介紹到這了,更多相關(guān)JAVA注解與反射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC后端Controller頁面跳轉(zhuǎn)的三種方式匯總
這篇文章主要介紹了SpringMVC后端Controller頁面跳轉(zhuǎn)的三種方式匯總,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10java枚舉類的屬性、方法和構(gòu)造方法應用實戰(zhàn)
這篇文章主要介紹了java枚舉類的屬性、方法和構(gòu)造方法應用,結(jié)合實例形式分析了java枚舉類的定義、構(gòu)造及相關(guān)應用操作技巧,需要的朋友可以參考下2019-08-08

詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決

關(guān)于shiro中部分SpringCache失效問題的解決方法

Java Email郵件發(fā)送簡單實現(xiàn)介紹