using java reflection to break  encapsulation

23
Using Java reflection to break encapsulation Spearker:LIN,CI-JIE

Upload: -

Post on 07-Aug-2015

30 views

Category:

Software


0 download

TRANSCRIPT

Using Java reflection to break  encapsulation

Spearker:LIN,CI-JIE

大綱介紹方法結論

介紹 程式碼的封裝機制用來保護物件內部元件,避免透漏太多物件內部的資訊給外界,造成工程師誤用這些 method或是 parameters而讓應用程式崩潰,此外程式碼的接續維護者也較能夠不去破壞到原有程式碼

Java 內部的 reflection機制可破壞原有程式碼的封裝機制,這個機制使 java能夠更彈性的執行程式,如此的動態能力讓程式碼不須寫死,當程式在執行過程中需要某些資源時再動態引入執行

Encapsulation說明 封裝 class能夠讓 classe改變內部的狀態時,不必修改開放給外部 class使用的 interface

封裝保護其他 class不會去影響到自身內部 class的狀態,當其他 class的內部狀態改變時,只要符合開放給其他 class使用的 public interface定義,就不必修改到自身內部 class狀態

Encapsulation方法 簡單的程式封裝方法可以使用private、 protected、 public這些 visible屬性去定義 class成員

或是使用 setter、 getter方法加入過濾機制,讓某些特定 class能夠取得 private的變數值

Reflection說明 Reflection這個名詞,在維基百科的解釋是「電腦程式用以觀察自身,及修改自身結構和行為的過程

透過 Reflection技巧,程式在執行時期本身便能夠得知自己的外觀長相,並且自我修改,甚至自我複製

相對於「執行時期」,未使用 Reflection機制的程式碼,在編譯時期便已為編譯器所見,物件所需類別無法在執行時再決定,靈活度相對較低

Reflection特性 在 Java中 Relfection機制的源頭,一個叫「 Class」的 class,此類別的每一個物件都用來表示系統中的每一個類別

每個 Class物件都描述了每個類別的相關資訊,也提供你透過它可以進行的一些操作

Class物件能「審視」自身的特性,這些特性包括了它隸屬於那個 Package、類別本身究竟是 Public還是Private、繼承自那一類別、成員變數以及成員函式

Reflection特性 透過這個自我審視的過程,程式能夠了解它所要處理的對象(尤其是型別未知的對象),具備了什麼特質

取得了某類別的成員變數後(在 Java中是以 Field類別的物件表示),便可以取得該類別物件的成員變數值,也可以設定其值。同樣的,取得了某類別的成員函式後(在 Java中是以 Method類別的物件表示),便可取得該成員函式的回傳型別、傳入的引數列表型別

在物件成員為 private狀態時,利用 reflection可動態取得或更改其值,程式封裝效果就被打破

大綱介紹方法結論

The Class Object

Java中 Class object可以用來描述任何物件特性,因此想要在執行過程中動態得知某個類別特性或成員特性,就需要得到類別所屬的 Class object

Java提供多種管道得到 Class object,只要得知類別名稱就可取得其所屬的 Class object,透過 Class object可以動態更改成員的 visible屬性

The Class Object

左圖為 Class object各種生成管道,其中最普遍使用Class.forname()方法

The Class Object

利用 Class object得到某類別的各項資訊

得到某類別的Class object

main()執行結果,包含 package name、 superclass、 visible屬性、繼承的interfaces

測試用 Class,實現 Observer interface

New Instance 取得某類別 Class object只是取得描述某類別的資訊而已,要對類別做操作需要此類別實體化的 instance

實體化類別方法在 java中定義 2種方法,一種是預設實體化方法,以預設 constructor來實體化類別,另一種為已自行定義的constructor來實體化物件

Private狀態的 constructor在正常 java定義中的實體化方法,是無法在其他類別中實體化此類別,透過 java reflection則可以突破此限制實體化類別

使用 reflection造成類別封裝效果消失,在有心人故意操弄下可能造成程式崩潰或是改變程式意圖

New Instance

實體化 Test1類別

Test1類別無法被存取,造成 exception

Constructor為 private狀態,無法被main()實體化 Test1 class

New Instance

利用 Class object取得 Test1 class資料,並將 constructor改為 public狀態

成功實體化 Test1 class,列印出 class名稱

不應該被其他 class實體化的Test1,因為 reflection機制而被實體化並破壞 Test1的實體化封裝機制

Field Access Field為在類別定義裡的變數成員 Private狀態的變數無法為其他類別所存取 使用 java reflection機制可以動態修改成員 visible狀態,造成成員變數資訊外洩,變數值可以被動態修改使程式意圖改變

Field Access

取得 Test1的成員” a”

Test1成員“ a”為private,造成AccessException

成員” a”為private狀態

Field Access

利用 reflection機制將 field的 private改為 public

動態將成員” a”的值從 0改為 1

因為 reflection機制動態改變成員變數 visible屬性和值,這破壞成員變數的封裝機制

Method Access Method為在類別定義裡的 function成員 Private狀態的 function無法為其他類別所存取 使用 java reflection機制可以動態修改成員 visible狀態,其他類別呼叫此 function改變程式流程步驟,使程式出現不在預期中的結果

Method Access

取得 Test1的成員 method “print”

Test1成員“ print”為private,造成AccessException

Test1成員” print”為private狀態

Method Access

利用 reflection機制,動態改變 visible為public動態呼叫 Text1的成員” print” method

成功呼叫” print” method印出字串

因為 reflection機制動態改變method visible屬性,這破壞成員 method的封裝機制

大綱介紹方法結論

結論 Reflection的設計主要不是用來破壞封裝 class的特性,是為了能夠讓程式碼執行時能夠更加靈活而設計

在使用 reflection時必須謹慎和小心,在可以不需要reflection時就不要使用,當要使用時盡可能的減少影響的範圍