需要上課的人員:
-
不瞭解JAVA Reflection的人員。
-
不瞭解Struts 2 中,JAVA的變數為何可以在JSP中使用的人員。
JAVA Reflection(映射)
在寫程式的時候,有時候會遇到一些比較特殊的情況,例如我有一個Class如下:
我想將它轉為JSON的格式,變成{name:"myname",age:18}這樣之類的,除了利用套件自動生成外,另一種方式是自己寫,如下:
可是這樣會遇到二個問題,第一個問題是:當我這個class因業務需求,加了一個屬性後,產生JSON的這段程式碼也要跟著變;第二個問題是:當我今天有N個屬性,我就是針對jObject.put這一段程式碼寫N次。難道不能讓它自動對應產生嗎?答案是可以的,這種對應的方法叫做Reflection。
Reflection的Field、Method定義
在JAVA的Reflection中,有一個專有名詞是Field,Field定義的是Class中的屬性,如下圖紅框的部份:
而Method的定為則為下方的紅框處:
這些定義都會在程式裡被用到。
JAVA Reflection實作
要利用Reflection的機制,必須先取得這一個Class,才能取得Class內的Field或Method,取得Class的方法很簡單,利用getClass即可,如下圖:
取得Class後,以本例來說,我們需要取得Class內的Field,所以透過getDeclaredFields的Method來取得這個Class內的Field。
我們可以利用Field的getName()來取得對應的變數文字,在本例中即是name與age。
再利用Field的get(Object o),此時傳入的參數為想要取得值的Object,也就Employee的物件。最後我們利用for each的方式,來取得每一個Field的name與Value,並將它塞入JSONObject中:
執行後的結果:
這就是Reflection的其中一種應用,另外Method是透過invoke的method來觸發,下方是網路上的範例:
Reflection很好用,但一開始不太好理解,需要多寫幾次才能理解。
JAVA命名規則
JAVA有一些命名規則,大致介紹如下:
-
Class:頭文字大寫,第二單詞以大寫相接。
-
Field變數:頭文字小寫,第二單詞以大寫相接。
-
Method:頭文字小寫,第二單詞以大寫相接。
-
Constant:全文字大寫,第二單詞以_(底線)相接。
如下圖範例:
遵守這些命名規則有什麼好處呢?因為有很多Framework是套用JAVA的命名規則來實作JAVA Reflection,所以這些Framework都是假設我們已經遵守這些命名規則了。
Framework與命名規則與Reflection實例
大多數的Framework在實作Reflection的功能時,是以Method的方式來實作的,而不是利用Field,這一點要請大家搞清楚,而且因應時機的不同,分別去觸發的Method也不同,以下圖的Struts2程式為例:
UserAction.java的程式碼如下:
JSP中的程式碼如下:
我們可以看到幾個重點:
-
在Action中的Method與Field是不相稱的,Method是setQ,而Field是query。
-
在JSP中的程式碼,name的屬性為q,所以送到後端時會變為q=xxx之類的參數。
這代表著前端使用者輸入的內容,在Action中會觸發setQ的Method,把值設進Field query之中。在這種狀況中,被觸發的Method是setQ,而且它並不會判斷是否有Field q及Method getQ存在與否(實際上並沒有getQ這個Method被宣告)。
上方的範例可以得到二個重點:
-
Method與Field可以不對稱。
-
set與get並不需要同時存在,而是視需求來撰寫。
Struts 2 其實是根據Request與Response來決定要呼叫get或set,Request時呼叫的是set Method,Response時呼叫的是get Method,這點請大家記清楚。
已實作Reflection的Framework
我們來談談有那些東西是套用命名規則與Reflection的套件吧:
-
Struts2
-
EL
-
JSTL
-
net.sf.json
-
Volecity
….等等,有太多的Framework都會實作Reflection,並利用「.」來區隔物件,例如user.name是先取得變數user的Object後,再去取得這個Object內的getName;所以請開發人員瞭解JAVA的命名規則,並實際運用在寫程式上,因為這些Framework都是以開發人員已經使用JAVA的命名規則為基礎來開發的。
作業-實作Reflection中的Method
請依下方的程式碼,實作setName與getName的Method。
留言列表