Java反射與註解的深度解析【2020最新版】

大千世界,茫茫人海,相識就是一種緣分。若此篇文章對您有幫助,點個贊或點個關注唄!

一、反射機制

1.1、反射機制的定義

  在運行狀態中,對於任意一個類,都能夠獲取類中的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;

1.2、反射機制的功能

  1. 在運行時判定任意一個對象所屬的類
  2. 在運行時構造任意一個類的對象
  3. 在運行時判定任意一個類所具有的成員變量和方法
  4. 在運行時調用任意一個對象的方法
  5. 生成動態代理

1.3、反射機制的作用

  1. 動態獲取在當前Java虛擬機中的類、接口或者對象信息
  2. 解除兩個類之間的耦合性,即在未得到依賴類的情況下,自身應用可以通過編譯
  3. 動態依賴注入(即需要某一類對象時動態生成類實例,並設置到被依賴的類中),減少編譯時的內存開銷

1.4、反射機制的實現原理

  運行時,通過ClassLoader查找到需要調用的類時,就會加載它並根據.class文件內記載的類型信息產生一個與該類相聯繫的獨一無二的Class對象,該Class對象記載了該類的字段,方法等信息,以後jvm要產生該類的實例,就是根據內存中存在的該Class類所記載的信息來進行。

1.5、獲取Class對象的三種方式

  1. 使用Class類的靜態方法: Class.forName(String name);
  2. 類的語法:T.class,代表了與其匹配的Class對象;
  3. 使用類的實例化的getClass方法: obj.getClass();

1.6、java.lang.Class類

1.6.1、獲取類的構造器java.lang.reflect.Constructor

  • public Constructor<?>[] getConstructors() 返回類中所有的public構造器集合,默認構造器的下標爲0;
  • public Constructor getConstructor(Class<?>… parameterTypes) 返回指定public構造器,參數爲構造器參數類型集合;
  • public Constructor<?>[] getDeclaredConstructors() 返回類中所有的構造器,包括私有;
  • public Constructor getDeclaredConstructor(Class<?>… parameterTypes) 返回任意指定的構造器;
  • Constructor重要的方法newInstance(Object …initargs) 實例化類;

1.6.2、獲取類的成員變量java.lang.reflect.Field

  • public Field[] getFields() 獲取所有的public成員變量;
  • public Field getField(String name) 獲取任意public成員變量;
  • public Field[] getDeclaredFields() 獲取所有的成員變量;
  • public Field getDeclaredField(String name) 獲取任意指定名字的成員變量;
  • public void setAccessible(boolean flag) 設置私有屬性是否可訪問;
  • Field 重要方法set(Object obj, Object value) 字段設置爲指定的新值。

1.6.3、獲取類的方法java.lang.reflect.Method

  • public Method[] getMethods() 獲取所有的共有方法的集合;
  • public Method getMethod(String name,Class<?>… parameterTypes) 獲取指定公有方法;
  • public Method[] getDeclaredMethods() 獲取所有的方法;
  • public Method getDeclaredMethod(String name,Class<?>… parameterTypes) 獲取任意指定方法;
  • Method重要方法invoke(Object obj ,Object…parmasType) 執行對象的方法,第一個參數爲類實例對象,第二個參數:對象方法的參數。

1.6.4、Class類的實例化方法

  newInstance()

1.6.5、獲取類的全名

  getName()

1.6.6、獲取類的簡稱

  getSimpleName()

1.6.7、獲取類的包名

  getPackage()

1.7、反射的性能分析

反射機制是一種程序自我分析的能力。用於獲取一個類的類變量,構造函數,方法,修飾符。
優點: 運行期類型的判斷,動態類加載,動態代理使用反射,反射提高了Java程序的靈活性和擴展性,降低耦合性,提高自適應能力。它允許程序創建和控制任何類的對象,無需提前硬編碼目標類;反射是其它一些常用語言,如C、C++、Fortran 或者Pascal等都不具備的。
缺點: 性能是一個問題,反射相當於一系列解釋操作,通知jvm要做的事情,性能比直接的java代碼要慢很多,因此Java反射機制主要應用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用。使用反射會模糊程序內部邏輯:程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術,因而會帶來維護問題。反射代碼比相應的直接代碼更復雜。

二、註解

2.1、基本概念

2.1.1、什麼是註解

  java提供了一種元程序中的元素關聯任何信息或者任何元數據的用途和方法;Annotation是JDK5.0後引入的,它可以用於創建文檔,跟蹤代碼中的依賴性,甚至執行基本編譯檢查。

2.1.2、Annotation的成員

  在Annotation類型中以無參的方法的形式被聲明。其方法名和返回值定義了該成員的名字和類型。

2.1.3、基本規則

  Annotation能被用來爲某個程序元素(類,方法,成員變量等)關聯任何的信息。Annotation不能影響程序代碼的執行,無論增加、刪除Annotation,代碼都始終如一的執行。

2.2、什麼是元數據metadata

2.2.1、根據所起的作用元數據分爲

  1. 編寫文檔:通過代碼裏標識的元數據文檔生成文檔;
  2. 代碼分析:通過代碼裏的標識的元數據對代碼進行分析;
  3. 編譯檢查:通過代碼裏標識的元數據讓編譯器能實現基本的編譯檢查;
  • 第一,元數據以標籤的形式存在與java代碼中;
  • 第二,元數據描述的信息是類型安全的,即元數據內部的字段都是有明確類型的;
  • 第三,元數據需要的編譯器之外的工具額外的處理用來生成其他的程序部件;
  • 第四,元數據可以只存在於java源代碼級別,亦可以存在於編譯之後的class文件內部;

2.3、Annotation和Annotation類型

  jdk5.0的新語法,他的行爲十分類似public、final這樣的修飾符每個Annotation具有一個名字和成員個數>=0每個成員具有被稱爲name=value對的名字和值,name=vlaue裝載了Annotation的信息。

2.4、註解的分類

根據註解參數個數分類:

  1. 標記註解
  2. 單值註解
  3. 完整註解

根據使用方法和用途分類:

  1. JDK內置系統註解(@Override :用於修飾此方法覆蓋了父類的方法、@Deprecated :用於修飾已經過時的方法、@SuppressWarnnings:用於通知編譯器禁止特定的編譯警告 )
  2. 元註解
  3. 自定義註解

2.5、系統內置標準註解

2.5.1、@Override

  限定重寫父類方法,@Override是一個標記註解類型,它被用來做標註方法。它說明了被標註的方法重寫了父類的方法,起到了斷言的作用。如果用在沒有覆蓋父類方法的方法時 編譯器會給出一個編譯錯誤!

2.5.2、@Deprecated

  標記已過時。同樣是是一個標記註解,當一個類型或成員使用@Deprecated修飾的話,編譯器將不鼓勵使用被標註的程序元素,而且這種修飾帶有"延續性"。

2.5.3、@SuppressWarnnings

  抑制編譯器警告,常被用於有選擇的關閉編譯器對類、方法、成員變量等的警告。@SuppressWarnnings不是一個標記註解。它有一個String[]的成員這個成員的值爲被禁止的警告名。
常見參數:

  1. deprecation:使用了不贊成使用的類或方法時警告;
  2. unchecked:執行了未檢查的轉換時警告;
  3. fallthrough:當switch程序塊直接通往下一種而沒有break時警告;
  4. path:在路徑、源文件路徑等重有不存在的路徑時警告;
  5. serial:當序列化的類上缺少seriaVersionUID定義時的警告;
  6. finally:任何finally字句不能正常完成時的警告;
  7. all:關於以上所有的警告

2.6、元註解meta-annotation

@Target:
作用:用於描述註解的適用範圍(即:被描述的註解可以用在什麼地方);
取值(ElementType)有:

  • OCNSTRUCTOR:用於描述構造器
  • FIELD:用於描述域
  • LOCAL_VARIABLE:用於描述局部變量
  • METHOD:用於描述方法
  • PACKAGE:用於描述包
  • PARAMETER:用於描述參數
  • TYPE:用於描述類、接口或enum聲明

@Retention:
作用:表示需要在什麼級別保存該註解信息,用於描述註解的生命週期(即 :被描述的註解在什麼範圍有效);
取值(RetentionPoicy)有:

  • SOURCE:在源文件中有效(即源文件保留);
  • CLASS:在class文件中有效(即class保留);
  • RUNTIME:在運行時有效(即運行時保留);

@Documented:
作用:Documented是一個標記註解,沒有成員,用於描述其他類型的annotation應該被作爲被標註的程序成員的公共API,因此可以被javadoc此類的工具文檔化。
@Inherited:
作用:Inherited 元註解是一個標記註解,闡述了某個被標記的註解是被繼承的。如果一個使用了@Inherited修飾的註解類型被用於一個class,則這個註解將比用於class的子類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章