java零基礎入門-高級特性篇(十五) 類載入與反射 2

繼續上一章的內容,當我們獲取到了類的Class對象,下面就可以用Class對象來干大事了。

反射

反射是什麼?反射是一種能力,能夠在程序運行的過程中獲取類的信息,創建對象,使用方法的能力。

反射

看名字,首先想到的是光的反射。我們能在鏡子裡面看見自己,因為光線照射在鏡子上,然後反射到我們眼睛裡,所以我們就能在鏡子里看見自己。這樣,我們可以通過觀察鏡子來獲取到我們自身的信息。java中的反射也有類似的特性,當一個java類載入到jvm後,生成了Class對象,這時候Class對象就像鏡子一樣,當我們在java應用程序中需要獲取到已載入的java類的信息時,通過反射這個功能,就可以做到。

反射獲取信息

反射獲取信息

反射包提供了很多的類型來獲取類的信息,上例中使用了最常用的幾種類型,分別是Constructor構造器類型,Method方法類型,Field成員變數類型,除了這幾種常用類型,還有各種方法用於判斷枚舉類,註解類,介面等等,同學們可以自行查閱API。上例中最重要的就是第一行獲取Class對象的方法,Class.forName()。一旦獲取到了Class對象,就可以通過該對象「反射」出一個類的各種信息。

反射創建對象

創建對象

在寫代碼的過程中,最常用的就是通過new關鍵字創建對象。但是反射給我們提供了另一種創建對象的思路,即是在運行時動態的創建對象。通過Class對象的newInstance()方法即可創建對象。上例中就是通過newInstance()方法創建對象的具體過程,需要注意的是,如果不指定構造器的話,newInstance()方法只能根據無參構造器創建對象。如果需要使用有參構造器,必須首先通過Class對象獲取指定構造器對象,再通過獲取的構造器來創建對象。

在獲取有參構造器的時候,也要注意一點。由於構造器是可以重載的,所以在獲取構造器的時候必須指定構造器的參數類型,這樣才能準確的找到我們需要的構造器。這也是重載構造器時,必須要指定不同類型或者不同數量的參數才能重載構造器的原因,在使用構造器的時候,必須有辦法能找出「唯一」符合要求的那個構造器。

反射調用方法

調用方法

反射調用方法的流程也與上面差不多,首先是獲取Class對象,有了Class對象再創建實例對象,然後獲取類的方法,最後用反射獲取的方法類調用方法。獲取方法和獲取構造器有點區別,構造器的名字都是與類名一致的,所以無需傳遞構造器的名稱,但是方法的名稱是自定義的,所以在通過Class對象獲取方法的時候,不但需要傳入方法參數的類型,還需要傳入方法名。

在調用方法的時候,和普通對象調用方法時一樣,都需要一個已經被創建好的對象。區別是通過new關鍵字創建的對象通過「.」來調用方法,而通過反射來調用方法是需要將實例對象作為參數,傳遞給Method類的對象的invoke()方法。這樣就能通過反射調用方法了。

反射使用舉例

講了這麼多反射的使用方法,具體該怎麼用呢?下面用一個例子來說一下。

在做項目的過程中,特別是web項目,有一個繞不開的問題就是不同類型直接進行值得傳遞。比如在頁面上輸入的數據格式與實際資料庫需要儲存的數據格式不同,這時候就需要把數據在不同的對象之間進行傳遞。

對象轉換

為什麼是不同的對象?因為後台服務必須為前台傳遞過來的數據準備好一個對象,前台傳過來什麼類型,後台就需要用這個格式來接收。比如頁面上的生日是個字元串格式「2011-11-11」,後台就需要一個特定的對象,這個對象需要用字元串類型的birthday變數來接收它,這個特定的對象通常叫做VO-視圖對象。

但是在資料庫裡面儲存的時候,有時候直接儲存字元串的日期格式會有不便,比如有一個業務需要按照年齡排序,如果是字元串格式的日期格式就會比較麻煩,需要很多額外的處理。所以有時候我們需要存的是Long類型,用來做比較的時候會十分方便,這就需要將頁面傳遞的字元串轉換為Long類型,用另一個birthday為Long類型的對象來接管。

然後程序員們就大筆一揮,不就是個類型轉換么,很簡單啊,看我的,我分分鐘搞定~

轉換

這個做法是非常常見的,工作中也會被大量使用,但是不建議這麼做,因為這個類的成員變數還算少,類型轉換也不算複雜,要是屬性多,從頭一個個轉下來,會有一大片一大片的轉換代碼,體力勞動必須想辦法避免。怎麼辦?體力勞動封裝成方法,傳入一個vo對象,一個dto對象,在方法里進行自動轉換就完了。這個方法里必須能夠獲取到兩個對象的所有信息才能轉換,這時候反射就派上用場了。

封裝方法

這個轉換的思路就是,首先從vo中遍歷出所有的屬性,然後從屬性中獲取對應的值,再根據屬性名為dto中對應的屬性賦值。要注意VO和DTO中的屬性都是私有的,所以在獲取值和設置值之前都必須通過setAccessible()將該屬性設置為可訪問,這樣就可以直接訪問私有變數,而無需通過方法中的set和get來獲取和設置屬性值。但是這樣做要注意,因為改變訪問權會破壞程序的封裝性。

這裡只是為了講解反射的作用簡單的寫了一個方法,其中還有不少的缺陷。其實在工作中有更好的方法完成這個任務,比如Apache提供了封裝好的JavaBean操作工具--BeanUtils。這個工具功能更加強大,並且提供了大量十分方便高效的工具方法,比如BeanUtils.copyproperties()這個方法就是上例的最好解決方法,並且在轉換中有更好的效率。

推薦閱讀:

相关文章