java中的九陽神功——反射原理(Class獲取方式)

編程語言 Java 九陽神功 技術 程序員界的彭于晏 2018-11-30
java中的九陽神功——反射原理(Class獲取方式)

1、什麼是反射技術?

動態獲取指定類以及類中的內容(成員),並運行其內容。

應用程序已經運行,無法在其中進行new對象的建立,就無法使用對象。這時可以根據配置文件的類全名去找對應的字節碼文件,並加載進內存,並創建該類對象實例。這就需要使用反射技術完成

其實,反射機制的非常重要的一個重要作用是可以在運行時動態地創建類的對象,示例:

package Java_ClassLoader;
public class GetClass {
public static void main(String[] args) {
try {
// 前面加上包名
// Class clazz = Class.forName("Java_ClassLoader.Sub");
Class clazz = Java_ClassLoader.Sub.class;
Base base = (Base) clazz.newInstance();
base.f();
} catch (Exception e) {
}
}
}
class Base {
public void f() {
System.out.println("Base");
}
}
class Sub extends Base {
public void f() {
System.out.println("Sub");
}
}

結果:

Sub

2、獲取class對象的三種方式

獲取Class對象的方式一:

通過對象具備的getClass方法(源於Object類的方法)。有點不方便,需要用到該類,並創建該類的對象,再調用getClass方法完成。

Person p = new Person();//創建Peron對象

Class clazz = p.getClass();//通過object繼承來的方法(getClass)獲取Person對應的字節碼文件對象

獲取Class對象的方式二:

每一個類型都具備一個class靜態屬性,通過該屬性即可獲取該類的字節碼文件對象。比第一種簡單了一些,僅用一個靜態屬性就搞定了。但是,還是有一點不方便,還必須要使用到該類。

Class clazz = Person.class;

獲取Class對象方式三:

去找找Class類中是否有提供獲取的方法呢?

* 找到了,static Class forName(className);

* 相對方便的多,不需要直接使用具體的類,只要知道該類的名字即可。

* 而名字完成可以作為參數進行傳遞 ,這樣就可以提高擴展性。

* 所以為了動態獲取一個類,第三種方式最為常用。

Class clazz = Class.forName("cn.itcast.bean.Person");//必須類全名

創建Person對象的方式:

以前:1,先加載cn.itcast.bean.Person類進內存。

2,將該類封裝成Class對象。

3,根據Class對象,用new操作符創建cn.itcast.bean.Person對象。

4,調用構造函數對該對象進行初始化。

cn.itcast.bean.Person p = new cn.itcast.bean.Person();

通過方式三:(此外還可以使用構造,構造可以指定參數---如String.class)

String className = "cn.itcast.bean.Person";

//1,根據名稱獲取其對應的字節碼文件對象

1,通過forName()根據指定的類名稱去查找對應的字節碼文件,並加載進內存。

2,並將該字節碼文件封裝成了Class對象。

3,直接通過newIntstance方法,完成該對象的創建。

4,newInstance方法調用就是該類中的空參數構造函數完成對象的初始化。

Class clazz = Class.forName(className);

//2,通過Class的方法完成該指定類的對象創建。

Object object = clazz.newInstance();//該方法用的是指定類中默認的空參數構造函數完成的初始化。

清單1,獲取字節碼文件中的字段。

Class clazz = Class.forName("cn.itcast.bean.Person");

//獲取該類中的指定字段。比如age

Field field = clazz.getDeclaredField("age");//clazz.getField("age"); //為了對該字段進行操作,必須要先有指定類的對象。

Object obj = clazz.newInstance();

//對私有訪問,必須取消對其的訪問控制檢查,使用AccessibleObject父類中的setAccessible的方法

field.setAccessible(true);//暴力訪問。建議大家儘量不要訪問私有

field.set(obj, 789);

//獲取該字段的值。

Object o = field.get(obj);

System.out.println(o);

備註:getDeclaredField:獲取所有屬性,包括私有。

getField:獲取公開屬性,包括從父類繼承過來的,不包括非公開方法。

清單2,獲取字節碼文件中的方法。

//根據名稱獲取其對應的字節碼文件對象

Class clazz = Class.forName("cn.itcast.bean.Person");

//調用字節碼文件對象的方法getMethod獲取class對象所表示的類的公共成員方法(指定方法),參數為方法名和當前方法的參數,無需創建對象,它是靜態方法

Method method = clazz.getMethod("staticShow", null);

//調用class對象所表示的類的公共成員方法,需要指定對象和方法中的參數列表

method.invoke(null, null);

………………………………………………………………………………………………………

Class clazz = Class.forName("cn.itcast.bean.Person");

//獲取指定方法。

Method method = clazz.getMethod("publicShow", null);

//獲取指定的類對象。

Object obj = clazz.newInstance();

method.invoke(obj, null);//對哪個對象調用方法,是參數組

好處:大大的提高了程序的擴展性。

總結:

1.三種方法可以獲取到Class類:

Class.forName("類的路徑")

類名.Class

實例.getClass()

2.四種創建對象的方法:

通過new語句實例化一個對象

通過反射機制創建對象,見上述例子

通過clone()方法創建一個對象

通過反序列化方式創建對象

相關推薦

推薦中...