
一 Java反射機(jī)制概述
我們都知道程序在運(yùn)行的時候要經(jīng)過編譯期和運(yùn)行期,編譯期就是編譯器吧源代碼翻譯成機(jī)器能識別的代碼,比如編譯器把Java代碼編譯成jvm識別的字節(jié)碼文件,而運(yùn)行期指的是將可執(zhí)行文件交給操作系統(tǒng)去執(zhí)行,JAVA反射機(jī)制就是在運(yùn)行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意個對象,都能夠調(diào)用他的任意方法和屬性;
這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為Java語言的反射機(jī)制
二 Java反射機(jī)制實(shí)現(xiàn)原理
Java語言編譯后會生成一個 .class文件,反射就是通過字節(jié)碼文件找到某一個類、類中的方法以及屬性。
反射的實(shí)現(xiàn)主要借助以下四個類:
Class: 類的對象
Constructor: 類的構(gòu)造方法
Filed: 類中的屬性對象
Method:類中的方法對象
1、獲取類對象:
通過類名獲取Class對象, Class<T> c = Class.forName("類的完全路徑");
通過CLass對象獲取具體的類對象: Object o = c.newInstance();
2、獲取類中的構(gòu)造方法
-
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一個 Constructor對象,它反映此Class對象所表示的類的指定公共構(gòu)造方法 -
public Constructor<?>[] getConstructors()
返回一個包含某些Constructor 對象的數(shù)組,這些對象反映此 Class 對象所表示的類的所有公共構(gòu)造方法 -
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一個 Constructor對象,該對象反映此Class對象所表示的類或接口的指定公共構(gòu)造方法
3、獲取類中的屬性
public native Field getDeclaredField(String name)
返回一個 Filed 對象,該對象反映此Class對象所表示的類或接口的指定已聲明字段public native Field[] getDeclaredFields()
返回Filed 對象的一個數(shù)組,這些對象反映此Class對象所表示的類或接口的指定已聲明字段public Field getField(String name)
返回一個 Filed 對象,他反映此 Class 對象所表示的類或接口的指定公共成員字段。public Field[] getFields()
返回一個包含某些 Filed 對象的數(shù)組,這些對象反映此 Class 對象所標(biāo)識的類或接口的所有課方訪問的公共成員字段。
4、獲取類中的方法
public Method getMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,他反映此 Class對象所表示的類或者接口的指定公共成員方法public Method[] getMethods()
返回一個包含某些 Method 對象的數(shù)組,這些對象反映此 Class對象所表示的類或者接口的公共 member 方法。public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,他反映此 Class對象所表示的類或者接口的指定已聲明方法public Method[] getDeclaredMethods()
返回 Method 對象的一個數(shù)組,這些數(shù)組反映此 Class對象所表示的類或者接口聲明的的所有方法,包括公共、保護(hù)、默認(rèn)訪問和私有方法,但布包繼承的方法
三 Java反射機(jī)制應(yīng)用場景代碼演示
public class LLPerson implements Serializable {
public String name;
public int age;
public LLPerson() {
}
public LLPerson(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(String something) {
Log.e("LLLLLLLL", "eat" + something);
}
//獲取類DemoTest的Class對象
Class c = null;
// 直接通過類名得到
c = LLPerson.class;
// 通過對象的 getClass() 方法獲取到
Object object = new LLPerson();
c = object.getClass();
// 通過全類名獲取,用的比較多,
c = Class.forName("com.example.liushaohua02.androidmolist.reflectActivity.LLPerson");
//打印該Class對象表示的類的名稱
Log.e(TAG, c.getName());
//獲取該類的實(shí)例
Log.e(TAG, "c:" + c.newInstance());
Log.e(TAG, "-------------------------------------------");
//獲取該類實(shí)現(xiàn)的接口
Class<?>[] interfaces = c.getInterfaces();
System.out.println(interfaces[0].getName());
Log.e(TAG, "-------------------------------------------");
//獲取有參構(gòu)造函數(shù)
Constructor<?> con = c.getConstructor(String.class, int.class);
LLPerson dt = (LLPerson) con.newInstance("xiaoming", 12);
Log.e(TAG, "age " + ((LLPerson) dt).getAge());
Log.e(TAG, "-------------------------------------------");
//獲取類的成員變量
Field f2 = c.getField("age");
Log.e(TAG, "Field" + f2);
//獲取指定對象上該字段表示的值
Log.e(TAG, "obj" + f2.get(dt));
Log.e(TAG, "-------------------------------------------");
//獲取指定的方法
Method m = c.getMethod("eat", String.class);
//反射調(diào)用方法,非常重要
m.invoke(dt, "麥當(dāng)勞");
四 Java 反射和 iOS 運(yùn)行時的對比
共同的優(yōu)點(diǎn):
- 都可以實(shí)現(xiàn)的功能:獲取類信息,屬性設(shè)置獲取,類的動態(tài)加載,方法的動態(tài)調(diào)用
- 提高程序的靈活性和擴(kuò)展性,能夠在運(yùn)行時動態(tài)的獲取類的實(shí)例
- 和動態(tài)編譯相結(jié)合,可以提高更強(qiáng)大的功能
- 提前無需硬編碼,便可以通過類名獲取對應(yīng)類的實(shí)例,進(jìn)而操作該實(shí)例。
不同點(diǎn): - OC 能動態(tài)的給 class 添加類和方法,Java 不行:OC 運(yùn)行時對 類方法的調(diào)用是通過全局名稱查詢,而 Java VM 是通過類似 C++的虛表機(jī)制。
此處想了解 OC的運(yùn)行時可看之前的一篇文章 《Runtime》