甜咖啡

          我的IT空間

          Java反射機(jī)制

          Java反射機(jī)制是Java語言被視為準(zhǔn)動(dòng)態(tài)語言的關(guān)鍵性質(zhì)。Java反射機(jī)制的核心就是允許在運(yùn)行時(shí)通過Java Reflection APIs來取得已知名字的class類的相關(guān)信息,動(dòng)態(tài)地生成此類,并調(diào)用其方法或修改其域(甚至是本身聲明為private的域或方法)。

          也許你使用Java已經(jīng)很長時(shí)間了,可是幾乎不會(huì)用到Java反射機(jī)制。你會(huì)嗤之以鼻地告訴我,Java反射機(jī)制沒啥用。或許在J2EE、J2SE等平臺,Java反射機(jī)制沒啥用(具體我也不了解,不多做評論),但是在Android應(yīng)用開發(fā)中,該機(jī)制會(huì)帶給你許多驚喜。

          如果熟悉Android,那么你應(yīng)該知道,Google不知出于什么原因,在系統(tǒng)源碼中一些類或方法中經(jīng)常加上“@hide”注釋標(biāo)記。它的作用是使這個(gè)方法或類在生成SDK時(shí)不可見,因此由此注釋的東西,你在編譯期是不可見的。這就出現(xiàn)了一些問題。一些明明可以訪問的東西編譯期卻無法訪問了!這使得你的程序有些本來可以完成的功能無法編譯通過。

          當(dāng)然,有一種辦法是自己去掉Android源碼中的所有“@hide”標(biāo)記,然后重新編譯一份自己的SDK。另一種辦法就是使用Java反射機(jī)制。當(dāng)然,你還可以利用反射來訪問存在訪問限制的方法和修改其域。不過這種使用方法比較特殊,我們在文章的最后單獨(dú)討論。

          從Class類說起

          如果你使用Java,那么你應(yīng)該知道Java中有一個(gè)Class類。Class類本身表示Java對象的類型,我們可以通過一個(gè)Object(子)對象的getClass方法取得一個(gè)對象的類型,此函數(shù)返回的就是一個(gè)Class類。當(dāng)然,獲得Class對象的方法有許多,但是沒有一種方法是通過Class的構(gòu)造函數(shù)來生成Class對象的。

          也許你從來沒有使用過Class類,也許你曾以為這是一個(gè)沒什么用處的東西。不管你以前怎么認(rèn)為,Class類是整個(gè)Java反射機(jī)制的源頭。一切關(guān)于Java反射的故事,都從Class類開始。

          因此,要想使用Java反射,我們首先得到Class類的對象。下表列出了幾種得到Class類的方法,以供大家參考。

          Class object 誕生管道

          示例

          運(yùn)用getClass()

          注:每個(gè)class 都有此函數(shù)

          String str = "abc";

          Class c1 = str.getClass();

          運(yùn)用

          Class.getSuperclass()

          Button b = new Button();

          Class c1 = b.getClass();

          Class c2 = c1.getSuperclass();

          運(yùn)用static method

          Class.forName()

          (最常被使用)

          Class c1 = Class.forName ("java.lang.String");

          Class c2 = Class.forName ("java.awt.Button");

          Class c3 = Class.forName ("java.util.LinkedList$Entry");

          Class c4 = Class.forName ("I");

          Class c5 = Class.forName ("[I");

          運(yùn)用

          .class 語法

          Class c1 = String.class;

          Class c2 = java.awt.Button.class;

          Class c3 = Main.InnerClass.class;

          Class c4 = int.class;

          Class c5 = int[].class;

          運(yùn)用

          primitive wrapper classes

          的TYPE 語法

          Class c1 = Boolean.TYPE;

          Class c2 = Byte.TYPE;

          Class c3 = Character.TYPE;

          Class c4 = Short.TYPE;

          Class c5 = Integer.TYPE;

          Class c6 = Long.TYPE;

          Class c7 = Float.TYPE;

          Class c8 = Double.TYPE;

          Class c9 = Void.TYPE;

          獲取一些基本信息

          在我們得到一個(gè)類的Class類對象之后,Java反射機(jī)制就可以大施拳腳了。首先讓我們來了解下如何獲取關(guān)于某一個(gè)類的一些基本信息。

          Java class 內(nèi)部模塊

          Java class 內(nèi)部模塊說明

          相應(yīng)之Reflection API,多半為Class methods。

          返回值類型(return type)

          package

          class隸屬哪個(gè)package

          getPackage()

          Package

          import

          class導(dǎo)入哪些classes

          無直接對應(yīng)之API。可間接獲取。

          modifier

          class(或methods, fields)的屬性

          int getModifiers()

          Modifier.toString(int)

          Modifier.isInterface(int)

          int

          String

          bool

          class name or interface name

          class/interface

          名稱getName()

          String

          type parameters

          參數(shù)化類型的名稱

          getTypeParameters()

          TypeVariable <Class>[]

          base class

          base class(只可能一個(gè))

          getSuperClass()

          Class

          implemented interfaces

          實(shí)現(xiàn)有哪些interfaces

          getInterfaces()

          Class[]

          inner classes

          內(nèi)部classes

          getDeclaredClasses()

          Class[]

          outer class

          如果我們觀察的class 本身是inner classes,那么相對它就會(huì)有個(gè)outer class。

          getDeclaringClass()

          Class

          上表中,列出了一些Java class內(nèi)部信息的獲取方式。所采用的方法幾乎都是調(diào)用Class對象的成員方法(由此你就可以了解到Class類的用處了吧)。當(dāng)然,表中所列出的信息并不是全部,有很大一部分沒有列出,你可以通過查閱Java文檔得到更全面的了解。另外,下面將重點(diǎn)介紹一下類的構(gòu)造函數(shù)、域和成員方法的獲取方式。

          類中最重要的三個(gè)信息

          如果要對一個(gè)類的信息重要性進(jìn)行排名的話,那么這三個(gè)信息理應(yīng)獲得前三的名次。它們分別是:構(gòu)造函數(shù)、成員函數(shù)、成員變量。

          也許你不同意我的排名,沒關(guān)系。對于Java反射來說,這三個(gè)信息與之前介紹的基本信息相比較而言,有著本質(zhì)的區(qū)別。那就是,之前的信息僅僅是只讀的,而這三個(gè)信息可以在運(yùn)行時(shí)被調(diào)用(構(gòu)造函數(shù)和成員函數(shù))或者被修改(成員變量)。所以,我想無可否認(rèn),至少站在Java反射機(jī)制的立場來說,這三者是最重要的信息。

          下面,讓我們分別了解一下這三個(gè)重要信息的獲取方式。另外,我們將在后面的章節(jié),詳細(xì)介紹他們的調(diào)用方式或者修改方式。

          構(gòu)造函數(shù)

          如果我們將Java對象視為一個(gè)二進(jìn)制的生活在內(nèi)存中生命體的話,那么構(gòu)造函數(shù)無疑可以類比為Java對象生命體的誕生過程。我們在構(gòu)造函數(shù)調(diào)用時(shí)為對象分配內(nèi)存空間,初始化一些屬性,于是一個(gè)新的生命誕生了。

          Java是純面向?qū)ο蟮恼Z言,Java中幾乎所有的一切都是類的對象,因此可想而知構(gòu)造函數(shù)的重要性。

          Java反射機(jī)制能夠得到構(gòu)造函數(shù)信息實(shí)在應(yīng)該是一件令人驚喜的事情。正因?yàn)榇?,反射機(jī)制實(shí)質(zhì)上才擁有了孵化生命的能力。換句話言之,我們可以通過反射機(jī)制,動(dòng)態(tài)地創(chuàng)建新的對象。

          獲取構(gòu)造函數(shù)的方法有以下幾個(gè):

          Constructor getConstructor(Class[] params) 

          Constructor[] getConstructors()

          Constructor getDeclaredConstructor(Class[] params) 

          Constructor[] getDeclaredConstructors()

          我們有兩種方式對這四個(gè)函數(shù)分組。

          首先可以由構(gòu)造函數(shù)的確定性進(jìn)行分類。我們知道,一個(gè)類實(shí)際上可以擁有很多個(gè)構(gòu)造函數(shù)。那么我們獲取的構(gòu)造函數(shù)是哪個(gè)呢?我們可以根據(jù)構(gòu)造函數(shù)的參數(shù)標(biāo)簽對構(gòu)造函數(shù)進(jìn)行明確的區(qū)分,因此,如果我們在Java反射時(shí)指定構(gòu)造函數(shù)的參數(shù),那么我們就能確定地返回我們需要的那個(gè)“唯一”的構(gòu)造函數(shù)。getConstructor(Class[] params) getDeclaredConstructor(Class[] params)正是這種確定唯一性的方式。但是,如果我們不清楚每個(gè)構(gòu)造函數(shù)的參數(shù)表,或者我們出于某種目的需要獲取所有的構(gòu)造函數(shù)的信息,那么我們就不需要明確指定參數(shù)表,而這時(shí)返回的就應(yīng)該是構(gòu)造函數(shù)數(shù)組,因?yàn)闃?gòu)造函數(shù)很可能不止一個(gè)。getConstructors()getDeclaredConstructors()就是這種方式。

          另外,我們還可以通過構(gòu)造函數(shù)的訪問權(quán)限進(jìn)行分類。在設(shè)計(jì)類的時(shí)候,我們往往有一些構(gòu)造函數(shù)需要聲明為“private”、“protect”或者“default”,目的是為了不讓外部的類調(diào)用此構(gòu)造函數(shù)生成對象。于是,基于訪問權(quán)限的不同,我們可以將構(gòu)造函數(shù)分為public和非public兩種。

          getConstructor(Class[] params) getConstructors()僅僅可以獲取到public的構(gòu)造函數(shù),而getDeclaredConstructor(Class[] params) getDeclaredConstructors()則能獲取所有(包括public和非public)的構(gòu)造函數(shù)。

          成員函數(shù)

          如果構(gòu)造函數(shù)類比為對象的誕生過程的話,成員函數(shù)無疑可以類比為對象的生命行為過程。成員函數(shù)的調(diào)用執(zhí)行才是絕大多數(shù)對象存在的證據(jù)和意義。Java反射機(jī)制允許獲取成員函數(shù)(或者說成員方法)的信息,也就是說,反射機(jī)制能夠幫助對象踐行生命意義。通俗地說,Java反射能使對象完成其相應(yīng)的功能。

          和獲取構(gòu)造函數(shù)的方法類似,獲取成員函數(shù)的方法有以下一些:

          Method getMethod(String name, Class[] params)

          Method[] getMethods()

          Method getDeclaredMethod(String name, Class[] params) 

          Method[] getDeclaredMethods() 

          其中需要注意,String name參數(shù),需要寫入方法名。關(guān)于訪問權(quán)限和確定性的問題,和構(gòu)造函數(shù)基本一致。

          成員變量

          成員變量,我們經(jīng)常叫做一個(gè)對象的域。從內(nèi)存的角度來說,構(gòu)造函數(shù)和成員函數(shù)都僅僅是Java對象的行為或過程,而成員變量則是真正構(gòu)成對象本身的細(xì)胞和血肉。簡單的說,就是成員變量占用的空間之和幾乎就是對象占用的所有內(nèi)存空間。

          獲取成員變量的方法與上面兩種方法類似,具體如下:

          Field getField(String name)

          Field[] getFields()

          Field getDeclaredField(String name)

          Field[] getDeclaredFields()

          其中,String name參數(shù),需要寫入變量名。關(guān)于訪問權(quán)限和確定性的問題,與前面兩例基本一致。

          讓動(dòng)態(tài)真正動(dòng)起來

          在本文的一開始就說,Java反射機(jī)制是Java語言被視為準(zhǔn)動(dòng)態(tài)語言的關(guān)鍵性質(zhì)。如果Java反射僅僅能夠得到Java類(或?qū)ο螅┻\(yùn)行時(shí)的信息,而不能改變其行為和屬性,那么它當(dāng)然算不上“動(dòng)態(tài)”。百度了一把何謂“動(dòng)態(tài)語言”,解釋如下:動(dòng)態(tài)語言,是指程序在運(yùn)行時(shí)可以改變其結(jié)構(gòu):新的函數(shù)可以被引進(jìn),已有的函數(shù)可以被刪除等在結(jié)構(gòu)上的變化。由此看來,Java確實(shí)不能算作“動(dòng)態(tài)語言”。但是和C、C++等純靜態(tài)語言相比,Java語言允許使用者在運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的classes,所以我們說Java是“準(zhǔn)動(dòng)態(tài)”語言。

          細(xì)心地讀者可能已經(jīng)發(fā)現(xiàn),在“類中最重要的三個(gè)信息”一節(jié)中,我們獲取的信息其實(shí)都是屬于類的,而不是對象。對于類的信息提取,其實(shí)并不涉及到對象內(nèi)存,在程序編譯完成的那一刻起,一切都已經(jīng)是確定的了。因此,它并不能算“動(dòng)態(tài)”。而如何對對象內(nèi)存進(jìn)行操作和訪問,才是“動(dòng)”的真正含義。

          說了這么多,關(guān)鍵還在于如何利用反射讓Java真正動(dòng)起來。下面我將按照創(chuàng)生、行為與屬性三個(gè)方面來介紹反射機(jī)制是如何讓Java動(dòng)的。

          創(chuàng)生

          不知是否本性使然,人類偏愛于思索起源與終結(jié)的話題。如果將程序類比于一個(gè)二進(jìn)制的世界的話,那么我們程序員則是這個(gè)世界的上帝。我們掌控著這個(gè)世界的起源和終結(jié),熟悉世界中一草一木的屬性和所有生靈的習(xí)性。現(xiàn)在就讓我們開始創(chuàng)世紀(jì)吧!

          在 “構(gòu)造函數(shù)”那一小節(jié)中,我們列出了獲取構(gòu)造函數(shù)的四種方法。這四種方法的返回值不知是否引起了各位的注意,那就是Constructor類。Constructor就類比于女媧吹給泥人的那一口真氣,有了它,一個(gè)生命才真正出現(xiàn)。

          Constructor支持泛型,也就是它本身應(yīng)該是Constructor<T>。這個(gè)類有一個(gè)public成員函數(shù),newInstance(Object... args),其中args為對應(yīng)的參數(shù)。我們正是通過它來實(shí)現(xiàn)創(chuàng)生的過程。

          行為

          行為踐行著生命的意義,而眾多事物的行為才得以構(gòu)成整個(gè)世界的運(yùn)轉(zhuǎn)。盡管道家的老子主張“無為而治”,宣揚(yáng)“圣人處無為之事,行不言之教”,但那是因?yàn)樗旧砭褪?nbsp;“無”的信仰者(“道”即“無”)。我們是唯物主義的信徒,所以必然要以“有”為價(jià)值。那么,在二進(jìn)制的世界里,我們?nèi)绾握{(diào)用Java對象的行為呢?

          同樣,我們首先回顧“成員函數(shù)”小節(jié)中四種方法的返回值。對,那就是Method類。此類有一個(gè)public成員函數(shù),Object invoke(Object receiver, Object... args)。我們能很好理解此函數(shù)的第二個(gè)參數(shù)args,它代表這個(gè)方法所需要接收的參數(shù)。也許大家對第一個(gè)參數(shù)receiver還存在疑惑之處。這得從編程語言的發(fā)展歷程講起。

          如果你關(guān)注幾種主流編程語言的起源,那么你能有這樣的印象:C從匯編而來,C++C而來,而JavaC/C++而來。有這樣一種印象就足夠了。從這樣的發(fā)展史我們可以看出,C++Java這兩種面向?qū)ο蟮木幊陶Z言都是從面向過程的C語言基礎(chǔ)上發(fā)展而來的。OOP是一種思想,它本身與編程語言無關(guān)。也就是說,我們用C也能寫出面向?qū)ο蟮某绦颍@也是C++Java能夠以C為基礎(chǔ)的根本所在。然而,C無法實(shí)現(xiàn)類似object.method()這種表現(xiàn)形式,因?yàn)?/font>C語言的結(jié)構(gòu)體中并不支持函數(shù)定義。那么我們用C實(shí)現(xiàn)OOP的時(shí)候,如何調(diào)用對象的方法呢?

          本質(zhì)上說,object.method()這種調(diào)用方式是為了表明具體method()的調(diào)用對象。而invoke(Object receiver, Object... args)的第一個(gè)參數(shù)正是指明調(diào)用對象。在C++中,object.method()其實(shí)是有隱含參數(shù)的,那就是object對象的指針,method原型的第一個(gè)參數(shù)其實(shí)是this指針,于是原型為method(void* this)。

          這樣一溯源,也許你更清楚了Object receiver參數(shù)的含義,或許更迷糊了?不管怎樣,歷史就是如此,只不過我個(gè)人能力有限,說不清楚而已。

          另外需要注意的是,如果某個(gè)方法是Java類的靜態(tài)方法,那么Object receiver參數(shù)可以傳入null,因?yàn)殪o態(tài)方法不從屬于對象。

          屬性

          同樣是人類,令狐沖和岳不群是如何被區(qū)分開的?那是因?yàn)樗麄冇兄煌膶傩?。同樣,同一個(gè)類可以生成多個(gè)對象,幾個(gè)同類型的對象之間如何區(qū)分?屬性起著決定性的作用。說到這里,想起一個(gè)科幻故事。人體瞬移機(jī),作用的根本原理就是人進(jìn)入A位置,被完全掃描之后,再在B位置重新組成它的細(xì)胞、血肉等屬性,從而完全創(chuàng)造出另一個(gè)一模一樣的人。當(dāng)然,這是唯物主義的極致,它假設(shè)了只要一切物質(zhì)相同,連記憶和靈魂都不會(huì)出現(xiàn)偏差,另外還存在倫理的問題,例如A位置的人會(huì)被銷毀掉嗎?

          盡管這是一個(gè)科幻,但是在程序的世界里,我們早已經(jīng)用上了這類似幻想的技術(shù)。Java中如何遠(yuǎn)程傳遞一個(gè)對象?我們已經(jīng)使用上了Java對象序列化的接口。不僅如此,利用序列化接口,我們甚至可以將一個(gè)生命保存起來,在需要的時(shí)候?qū)⑺鼜?fù)活,這就是對象的持久化。不得不感慨,在程序的世界里,我們就是上帝啊!

          對象序列化如此強(qiáng)大,那么它的本質(zhì)是什么呢?它的工作原理是怎樣的呢?簡單的說,對象序列化的本質(zhì)就是屬性的序列化。原理就是我們崇尚的唯物主義,如果同一個(gè)類的兩個(gè)對象所有屬性值都完全相同,那么我們可以認(rèn)為這是同一個(gè)對象。

          說了這么多,只是想說明一件事情,屬性對于對象而言是多么的重要。那么如何讀寫對象中屬性的值呢?回顧獲取屬性信息的方法返回值類型,那是Field。Field類有兩個(gè)public方法,分別對應(yīng)讀與寫,它們是:

          Object get(Object object)

          void set(Object object, Object value)

          object參數(shù)需要傳入的對象,原理類似于成員方法需要指明對象一樣。如果是靜態(tài)屬性,此值同樣可以為null。

          關(guān)于反射的一些高級話題

          如果說前面那些屬于Java反射的基本知識,那么在文章的最后,我們來探討一下反射的一些高級話題。另外,本文對基礎(chǔ)知識的講解僅屬于抓主干,具體的一些旁支可以自己參看文檔。需要提一下的是,Java反射中對數(shù)組做過單獨(dú)的優(yōu)化處理,具體可查看java.lang.reflect.Array類;還有關(guān)于泛型的支持,可查看java.lang.reflect.ParameterizedType及相關(guān)資料。

          暫時(shí)想到的高級話題有三個(gè),由于對Java反射理解的也不算深入,所以僅僅從思路上進(jìn)行探討,具體實(shí)現(xiàn)上,大家可以參考其他相關(guān)資料,做更深入研究。

          Android編譯期問題

          Android的安全權(quán)限問題我把它簡單的劃分成三個(gè)層次,最不嚴(yán)格的一層就是僅僅騙過編譯器的“@hide”標(biāo)記。對于一款開源的操作系統(tǒng)而言,這個(gè)標(biāo)記本身并不具備安全上的限制。不過,從上次Google過來的負(fù)責(zé)Android工程師的說法來看,這個(gè)標(biāo)記的作用更多的是方便硬件廠商做閉源的二次開發(fā)。這樣解釋倒也說得過去。

          不過這并不影響我們使用反射機(jī)制以繞過原生Android的第一層安全措施。如果你熟悉源碼的話,會(huì)發(fā)現(xiàn)這可以應(yīng)用到很多地方。并且最關(guān)鍵的是你并不需要放在源碼中編譯,而是像普通應(yīng)用程序的開發(fā)過程一樣。

          具體使用范圍我不能一一列舉了,例如自定義窗口、安裝程序等等。簡單的說,在Android上使用反射技術(shù),你才會(huì)對Android系統(tǒng)有更深的理解和更高的控制權(quán)。

          軟件的解耦合

          我們在架構(gòu)代碼的時(shí)候,經(jīng)常提到解耦合、弱耦合。其實(shí),解耦和不僅僅只能在代碼上做文章。我們可以考慮這樣一種情況:軟件的功能需求不可能一開始就完全確定,有一些功能在軟件開發(fā)的后期甚至是軟件已經(jīng)發(fā)布出去之后才想到要加入或者去掉。

          按我們慣有的思維,這種情況就得改動(dòng)源碼,重新編譯。如果軟件已經(jīng)發(fā)布出去,那么就得讓客戶重新安裝一次軟件。反思一下,我們是否認(rèn)為軟件和程序是同一回事呢?事實(shí)上,如果你能將軟件和程序分開來理解,那么你會(huì)發(fā)現(xiàn),為了應(yīng)對以上的情況,我們還有其他的解決辦法。

          我國有一個(gè)很重要但是很麻煩的制度,那就是戶籍制度。它的本意是為了更好的管理人口事宜。每當(dāng)一個(gè)孩子出生,我們就需要在戶籍管理的地方去給他辦理戶籍入戶;而每當(dāng)一個(gè)人去世,我們也需要在相應(yīng)的地方銷去他的戶籍。既然我們可以視類為生命,那么我們能否通過學(xué)習(xí)這樣的戶籍管理制度來動(dòng)態(tài)地管理類呢?

          事實(shí)上這樣的管理是可行的,而且Java虛擬機(jī)本身正是基于這樣的機(jī)制來運(yùn)行程序的。因此我們是否可以這樣來架構(gòu)軟件框架。首先,我們的軟件有一個(gè)配置文件,配置文件其實(shí)是一個(gè)文本,里面詳細(xì)描述了,我們的軟件核心部分運(yùn)行起來后還需要從什么路徑加載些什么類需要何時(shí)調(diào)用什么方法等。這樣當(dāng)我們需要加或減某些功能時(shí),我們只需要簡單地修改配置文本文件,然后刪除或者添加相應(yīng)的.class文件就可以了。

          如果你足夠敏感,你或許會(huì)發(fā)現(xiàn),這種方式形成的配置文件幾乎可以相當(dāng)于一門腳本語言了。而且這個(gè)腳本的解釋器也是我們自己寫的,另外關(guān)鍵是它是開發(fā)的,你可以為它動(dòng)態(tài)地加入一些新的類以增加它的功能。

          不要以為這僅僅是一個(gè)設(shè)想,雖然要開發(fā)成一門完備的腳本語言確實(shí)比較麻煩。但是在一些網(wǎng)絡(luò)端的大型項(xiàng)目中,通過配置文件 + ClassLoader + 反射機(jī)制結(jié)合形成的這種軟件解耦和方式已經(jīng)用得比較普遍了。

          所以,在此我不是在提出一種設(shè)想,而是在介紹業(yè)界處理此類問題的一種解決方案。

          反射安全

          文章讀到這里,我想你應(yīng)該由衷地感嘆,Java反射機(jī)制實(shí)在是太強(qiáng)大了。但是,如果你有一些安全意識的話,就會(huì)發(fā)現(xiàn)Java這個(gè)機(jī)制強(qiáng)大得似乎有些過頭了。前面我們提到,Java反射甚至可以訪問private方法和屬性。為了讓大家對Java反射有更全面的了解,樹立正確的人生觀價(jià)值觀,本小節(jié)將對Java的安全問題做一個(gè)概要性的介紹。

          相對于C++來說,Java算是比較安全的語言了。這與它們的運(yùn)行機(jī)制有密切的關(guān)系,C++運(yùn)行于本地,也就是說幾乎所有程序的權(quán)限理論上都是相同的。而Java由于是運(yùn)行于虛擬機(jī)中,而不直接與外部聯(lián)系,所以實(shí)際上Java的運(yùn)行環(huán)境是一個(gè)“沙盒”環(huán)境。

          Java的安全機(jī)制其實(shí)是比較復(fù)雜的,至少對于我來說是如此。作為Java的安全模型,它包括了:字節(jié)碼驗(yàn)證器、類加載器、安全管理器、訪問控制器等一系列的組件。之前文中提到過,我把Android安全權(quán)限劃分為三個(gè)等級:第一級是針對編譯期的“@hide”標(biāo)記;第二級是針對訪問權(quán)限的private等修飾;第三級則是以安全管理器為托管的Permission機(jī)制。

          Java反射確實(shí)可以訪問private的方法和屬性,這是繞過第二級安全機(jī)制的方法(之一)。它其實(shí)是Java本身為了某種目的而留下的類似于“后門”的東西,或者說是為了方便調(diào)試?不管如何,它的原理其實(shí)是關(guān)閉訪問安全檢查。

          如果你具有獨(dú)立鉆研的精神的話,你會(huì)發(fā)現(xiàn)之前我們提到的Field、MethodConstructor類,它們都有一個(gè)共同的父類AccessibleObject 。AccessibleObject 有一個(gè)公共方法:void setAccessible(boolean flag)。正是這個(gè)方法,讓我們可以改變動(dòng)態(tài)的打開或者關(guān)閉訪問安全檢查,從而訪問到原本是private的方法或域。另外,訪問安全檢查是一件比較耗時(shí)的操作,關(guān)閉它反射的性能也會(huì)有較大提升。

          不要認(rèn)為我們繞過了前兩級安全機(jī)制就沾沾自喜了,因?yàn)檫@兩級安全并不是真正為了安全而設(shè)置的。它們的作用更多的是為了更好的完善規(guī)則。而第三級安全才是真正為了防止惡意攻擊而出現(xiàn)的。在這一級的防護(hù)下,你甚至可能都無法完成反射(ReflectPermission),其他的一切自然無從說起。

          posted on 2012-05-17 17:07 甜咖啡 閱讀(276) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          <2012年5月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          統(tǒng)計(jì)

          • 隨筆 - 88
          • 文章 - 2
          • 評論 - 16
          • 引用 - 0

          常用鏈接

          留言簿(1)

          我參與的團(tuán)隊(duì)

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 沁阳市| 寻乌县| 乌拉特中旗| 北碚区| 成都市| 永新县| 大名县| 清流县| 福泉市| 民乐县| 兰溪市| 潜山县| 县级市| 邵武市| 镇赉县| 通河县| 陈巴尔虎旗| 蓬莱市| 泊头市| 页游| 建平县| 渭源县| 新兴县| 建始县| 永丰县| 庆阳市| 抚州市| 剑川县| 新安县| 元朗区| 正安县| 涿州市| 莲花县| 尖扎县| 大安市| 封开县| 连平县| 昂仁县| 乌什县| 连南| 长子县|