自己對反射的理解和應(yīng)用還處于比較淺顯的階段,寫這篇文章更多在于整理總結(jié)姥卢,也就是幫助自己進(jìn)一步的理解和學(xué)習(xí)反射機(jī)制摔蓝。
反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問盏触、檢測和修改它本身狀態(tài)或行為的一種能力渗蟹。
java中類反射
反射是 Java 程序開發(fā)語言的特征之一块饺,它允許運(yùn)行中的 Java 程序?qū)?strong>自身進(jìn)行檢查,或者說“自審”拙徽,并能直接操作程序的內(nèi)部屬性和方法刨沦。
簡單總結(jié)這些定義,那就是反射可以讓我們獲得一個(gè)類的所有信息膘怕,包括私有屬性和私有方法想诅,對于我們這種小白,先知道這點(diǎn)就可以啦岛心,那在java中如何使用發(fā)射呢来破。這里我們隨便創(chuàng)建一個(gè)類來演示。比如說創(chuàng)建一個(gè)Book類:
public class Book implements Parcelable
{
private int id=1;
private String name="android";
private String author="wf";
private String getName()
{
return name;
}
}
Book類中屬性和方法都是私有的忘古,現(xiàn)在我們通過反射來訪問這些屬性和方法徘禁。
String s = null;
try
{
Class<?> bookClass = Class.forName("cc.abto.demo.Book");//完整類名
Object book = bookClass.newInstance();//獲得實(shí)例
Method getAuthor = bookClass.getDeclaredMethod("getName");//獲得私有方法
getAuthor.setAccessible(true);//調(diào)用方法前,設(shè)置訪問標(biāo)志
s = (String) getAuthor.invoke(book);//使用方法
}
catch (Exception e)
{
e.printStackTrace();
}
可以看到上面代碼中我們用Class和Method這兩個(gè)類完成了反射髓堪,這兩個(gè)類分別對應(yīng)了類和方法送朱,也就是包裝了類和方法的信息,下面對反射的部分API做一下簡單介紹:
- Class類:代表一個(gè)類干旁,位于java.lang包下
- Field類:代表類的成員變量(成員變量也稱為類的屬性)
- Method類:代表類的方法
- Constructor類:代表類的構(gòu)造方法
- Array類:提供了動態(tài)創(chuàng)建數(shù)組驶沼,以及訪問數(shù)組的元素的靜態(tài)方法
在Java中,每個(gè)class都有一個(gè)相應(yīng)的Class對象争群。也就是說回怜,當(dāng)我們編寫一個(gè)類,編譯完成后换薄,在生成的.class文件中玉雾,就會產(chǎn)生一個(gè)Class對象,用于表示這個(gè)類的類型信息轻要。 java中的Class三種獲取方式:
//使用Class類的靜態(tài)方法forName()复旬,用類的名字獲取一個(gè)Class實(shí)例
Class<?> bookClass = Class.forName("cc.abto.demo.Book");
//利用對象調(diào)用getClass()方法獲取該對象的Class實(shí)例
Book book = new Book();
Class<? extends Book> bookClass = book.getClass();
//運(yùn)用.class的方式來獲取Class實(shí)例,對于基本數(shù)據(jù)類型的封裝類伦腐,還可以采用.TYPE來獲取相對應(yīng)的基本數(shù)據(jù)類型的Class實(shí)例
Class<Book> bookClass = Book.class;
Class<Integer> type = Integer.TYPE;
然后再貼一些常用的方法
public Annotation[] getAnnotations () //獲取這個(gè)類中所有注解
getClassLoader() //獲取加載這個(gè)類的類加載器
getDeclaredMethods() //獲取這個(gè)類中的所有方法
getReturnType() //獲取方法的返回類型
getParameterTypes() //獲取方法的傳入?yún)?shù)類型
isAnnotation() //測試這類是否是一個(gè)注解類
getDeclaredConstructors() //獲取所有的構(gòu)造方法
getDeclaredMethod(String name, Class… parameterTypes)// 獲取指定的構(gòu)造方法(參數(shù):參數(shù)類型.class)
getSuperclass() //獲取這個(gè)類的父類
getInterfaces()// 獲取這個(gè)類實(shí)現(xiàn)的所有接口
getFields() //獲取這個(gè)類中所有被public修飾的成員變量
getField(String name) //獲取指定名字的被public修飾的成員變量
newInstance() //返回此Class所表示的類赢底,通過調(diào)用默認(rèn)的(即無參數(shù))構(gòu)造函數(shù)創(chuàng)建的一個(gè)新實(shí)例
更多的方法和方法的注解大家可以查看文檔。
Android中的簡單應(yīng)用
查看Android SDK的源碼時(shí)候柏蘑。你會發(fā)現(xiàn)很多類或方法中經(jīng)常加上了“@hide”注釋標(biāo)記幸冻,這些API是不允許在程序中調(diào)用的。Hidden API之所以被隱藏咳焚,是想阻止開發(fā)者使用SDK中那些未完成或不穩(wěn)定的部分(接口或架構(gòu))洽损。如圖所示
所以在開發(fā)中,我們不僅可以通過反射獲取私有屬性和方法革半,也可以利用反射獲取一些SDK對外部隱藏的API碑定,比如說前陣子在做藍(lán)牙開發(fā)的時(shí)候流码,自動配對的一些方法在API 19以后才對外開放的,這邊我們就可以使用反射來實(shí)現(xiàn)配對功能了
try
{
Class<BluetoothDevice> bluetoothDeviceClass = BluetoothDevice.class;
bluetoothDeviceClass.getMethod("setPin", byte[].class).invoke(device, "1234".getBytes());
bluetoothDeviceClass.getMethod("createBond").invoke(device);
bluetoothDeviceClass.getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
bluetoothDeviceClass.getMethod("cancelPairingUserInput").invoke(device);
}
catch (Exception e)
{
e.printStackTrace();
}
反射的好處
反射不僅可以讓我們獲得隱藏的方法和屬性延刘,還可以讓對象的實(shí)例化從編譯時(shí)轉(zhuǎn)化為運(yùn)行時(shí)漫试,因?yàn)槲覀兛梢酝ㄟ^Class.forName("cc.abto.demo.Book").newInstance()的方法來生成新的實(shí)例,而這邊的"cc.abto.demo.Book"是一個(gè)字符串碘赖,完全可以用變量來代替驾荣,再結(jié)合抽象工廠模式什么的,我們就可以很大程度上對程序應(yīng)用中的功能模塊進(jìn)行解耦合普泡〔ブ溃可能這邊簡單幾句沒能解釋清楚,大家可以看看《大話設(shè)計(jì)模式》之類的書撼班,里面就介紹的比較清楚明白了歧匈。
反射的弊端
反射帶來的兩大弊端可能就是安全和性能問題了吧,這方面我知之甚少砰嘁,有待進(jìn)一步的了解和學(xué)習(xí)件炉。
最后
因?yàn)樽约核接邢蓿绻行╁e(cuò)誤的地方還請大家見諒矮湘。下面貼出幾篇寫得比較好和詳細(xì)的博客妻率。
【Android】 認(rèn)識反射機(jī)制(Reflection)
Java反射機(jī)制的原理及在Android下的簡單應(yīng)用
java中的反射機(jī)制
Android注解與反射機(jī)制