天天看點

JavaSE---反射反射是什麼?反射有什麼意義?反射如何使用?Class類詳解反射的應用場景調用指定的方法擷取注解資訊提高反射效率

文章目錄

  • 反射是什麼?
  • 反射有什麼意義?
  • 反射如何使用?
  • Class類詳解
    • class類
    • Class類常用方法
    • 建立class對象
  • 反射的應用場景
  • 調用指定的方法
  • 擷取注解資訊
  • 提高反射效率

前言: 反射就像是一面鏡子,這面鏡子其實就是JVM,他能照出你的類的所有屬性和方法,也能調用你所有對象的屬性和方法, crazy~

java

是一門靜态語言(運作時結構不變),不像

JavaScript,python...

那些動态語言一樣,在運作時可以修改變量的值,但是java也可以稱為

準動态語言

,因為他可以利用反射機制,獲得類似動态語言的效果。

反射是什麼?

  • 先說正是怎麼一回事。我要使用某個類,我必須要知道它是什麼類,有何作用?用的時候,要先執行個體化。
//執行個體化一個對象,執行個體化的過程牽扯太多,不贅述
Student stu = new Studnt();
Class c1 = stu.getClass();
System.out.println(c1.getName());
           
  • 上面這個Student類,JVM在加載的時候這個類的時候,其實會在JAVA堆中建立一個

    java.lang.class類

    的對象,就是上面的

    c1

    ,這個class對象代表類的相關資訊。可以使用這個對象的一些方法來擷取類的相關資訊,這裡也展現出了萬物皆對象的理念,連類都是對象。
  • 看看class類,這還隻是一小部分方法,跟類相關的都可以在Class類中找到。
    JavaSE---反射反射是什麼?反射有什麼意義?反射如何使用?Class類詳解反射的應用場景調用指定的方法擷取注解資訊提高反射效率
  • 那說了這麼多,反射到底是什麼呢?

我的了解:在運作狀态中,可以知道任意一個類的屬性和方法,也可以調用任意一個對象的屬性和方法,也就是動态擷取資訊,動态擷取對象方法和屬性,然而這些底層的實作細節都被屏蔽了,隻留下API庫給我們使用,也就是

java.lang.reflect

類庫,這些API學習并不難,難在了解反射這個概念,由于實作細節都被屏蔽了,我們也就很少寫到反射的代碼。

反射有什麼意義?

我直接

new

出來一個對象不就可以了,為什麼用反射,要兜個大圈子?其實出去這些淺顯表面的,反射真正的意義在于提高程式的靈活性,屏蔽底層實作細節,便于使用。

反射如何使用?

這個在使用的時候直接查API即可,常用的有以下幾種。

  • 通過一個對象獲得完整的包名和類名。
  • 執行個體化Class對象。
  • 擷取一個對象的父類與實作的接口。
  • 擷取某個類的全部構造函數。
  • 通過反射機制執行個體化一個對象。
  • 擷取某個類的全部屬性
  • 擷取某個類的全部方法

Class類詳解

class類

  • 對象照鏡子後可以得到的資訊:某個類的屬性,方法,構造器,以及實作了哪些接口。
  • 對每個類而言,JRE都為其保留一個不變的Class類型的對象,一個Class對象包含了特定某個結構(

    class/interface/enum/annotation/primitive type/void/[]

    )的有關資訊。
  1. Class本身也是一個類。
  2. Class對象隻能由系統建立。我們隻能通過反射去得到。
  3. 一個加載的類在JVM中隻會有一個Class執行個體。
  4. Class類是Reflection的根源,如果你想動态加載,運作的類,隻有先獲得相應的class對象才可以。

Class類常用方法

方法名 功能說明

static ClassforName(String name)

傳回指定類名name的Class對象

Object newInstence()

通過反射建立對象,傳回Class對象的一個執行個體

getName()

傳回Class對象所表示的實體(類,接口,數組的名稱)

Class getSuperClass()

傳回目前Class對象的父類的Class對象

Class[] getInterdaces()

擷取目前class對象的接口

ClassLoader getClassLoader()

傳回該類的類加載器

Constructor[] getConstructor()

傳回一個包含某些Constructor對象的數組

建立class對象

建立class對象的三種方式

  • 通過對象獲得
  • forname獲得
  • 通過類名.class獲得
JavaSE---反射反射是什麼?反射有什麼意義?反射如何使用?Class類詳解反射的應用場景調用指定的方法擷取注解資訊提高反射效率

反射的應用場景

  • JDBC(連接配接資料庫與後端的橋梁),這其中就牽扯到一個連接配接的問題,我們将資料庫的連接配接資訊(使用者名,使用者密碼,庫名…)寫在配置檔案裡,而不是寫在代碼裡,為什麼?因為這樣我們更換資料庫的時候,隻需要改配置資訊,而不是去改代碼。而這裡的由配置檔案到代碼,就是由反射來加載驅動的。
  • Spring MVC,學

    servlet

    的時候各種

    getParameter()

    擷取資訊,但是在SpringMVC架構中隻需要在

    javaBean

    中約定好字段名,就可以把值填充進去。這就是反射的好處。
  • Spring,這個我學的還不多,但是涉及到一個自動組裝的問題,隻要字段名的順序是約定一緻的,就可使實作自動組裝的效果,就像一個蘿蔔一個坑一樣。如果順序颠倒,可能在你想象中組裝出來的是超跑,但是現實卻是拖拉機。
  • Java的反射用的最多的地方就是在架構裡面。比如說有兩個程式員,他們各自建立了兩個類,第一個程式員現在需要第二個程式員建立的類,可是現在第二個程式員建立的類還沒有完成。那麼第一個程式員編譯自然不成功,但是現在第一個程式員又要使用第二個程式員的類,這個時候,反射就可以完成這個任務。因為反射是在類運作的時候擷取對象的各個資訊,是以第一個程式員的類就可以完成編譯了。

調用指定的方法

  • 通過反射,調用類中的方法,通過Method類完成。
  1. 擷取到類的class對象。
  2. 通過Class對象調用

    getMethod(String name, Class ...parameterTypes)

    方法擷取一個

    Method

    對象,并設定此方法操作時所需要的參數類型。
  3. 使用

    Object invoke(Object obj,Object[] args)

    進行調用,并向方法中傳遞要設定的obj對象的參數資訊。
  • setAccessible

    :啟動和禁用通路安全檢查的開關。預設為false,設定為true之後,可以通路一些私有屬性,可以提高反射的效率,如果代碼中必須用反射,而該句代碼需要頻繁的被調用,就設定為true。
JavaSE---反射反射是什麼?反射有什麼意義?反射如何使用?Class類詳解反射的應用場景調用指定的方法擷取注解資訊提高反射效率

擷取注解資訊

提高反射效率

  1. 反射比new對象慢,是因為Class.forName這個方法比較耗時,它實際上調用了一個本地方法,通過這個方法來要求JVM查找并加載指定的類。是以我們在項目中使用的時候,可以把Class.forName傳回的Class對象緩存起來,下一次使用的時候直接從緩存裡面擷取,這樣就極大的提高了擷取Class的效率。同理,在我們擷取Constructor、Method等對象的時候也可以緩存起來使用,避免每次使用時再來耗費時間建立。
  2. 還有一種更極緻的使用反射手法,一個高性能反射工具包ReflectASM。它是通過位元組碼生成的方式來實作的反射機制
  3. 總結一下,為了更好的使用反射,我們應該在項目啟動的時候将反射所需要的相關配置及資料加載進記憶體中,在運作階段都從緩存中取這些中繼資料進行反射操作。如果對性能有極緻追求的時候,可以考慮通過三方包,直接對位元組碼進行操作。