天天看點

[Java開發之路](14)反射機制

1. class類

普通對象構造方式:

<code>// 建立book執行個體對象</code>

<code>book book = new book();</code>

對于class的執行個體對象如何構造呢?

class的構造函數是私有的,隻有jvm才能建立執行個體對象

<code>// class的構造函數是私有的,隻有jvm才能建立class執行個體對象</code>

<code>class class1 = new class(); // 錯誤</code>

<code>public final class class&lt;t&gt; implements java.io.serializable,</code>

<code>java.lang.reflect.genericdeclaration,</code>

<code>java.lang.reflect.type,</code>

<code>java.lang.reflect.annotatedelement {</code>

<code> </code>

<code>/*</code>

<code>* constructor. only the java virtual machine creates class</code>

<code>* objects.</code>

<code>*/</code>

<code>private class() {}</code>

<code>....</code>

<code></code>

<code>}</code>

class有三種表示方式:

(1)xxx.class  xxx為類名  

實際再告訴我們任何一個類都有一個隐含的已經太成員變量class

<code>class class1 = book.class;</code>

(2)xxx.getclass()  xxx為對象名稱

已知該類的執行個體對象,通過getclass()方法擷取

<code>class class2 = book.getclass();</code>

(3)通過class類的forname方法擷取  

<code>try {</code>

<code>class class3 = class.forname("com.qunar.bean.book");</code>

<code>system.out.println(class1 == class2);</code>

<code>system.out.println(class1 == class3);</code>

<code>} catch (classnotfoundexception e) {</code>

<code>e.printstacktrace();</code>

我們完全可以通過類的類類型建立該類的對象執行個體,通過class1,class2以及class3建立book的執行個體

<code>// 通過類類型的newinstance方法建立執行個體對象</code>

<code>book book2 = (book)class3.newinstance();</code>

<code>book2.setprice("23.4");</code>

<code>} catch (instantiationexception e) {</code>

<code>} catch (illegalaccessexception e) {</code>

2. class動态加載類

class.forname("類的全稱")  不僅表示了類的類類型,還代表了動态加載類。

編譯時刻加載類是靜态加載類,運作時刻加載類是動态加載類。

3.反射

反射機制--用來檢查可用的方法,并傳回方法名。

人們想要在運作時擷取類的資訊的另一個動機,便是希望提供在跨網絡的遠端平台上建立和運作對象的能力。這被稱為遠端方法調用,它允許一個java程式将對象分布到多台機器上。

class類與java.lang.reflect類庫一起對反射的概念進行了支援,該類庫包含了filed,method以及constructor類(每個類都實作了member接口)。這些類型的對象是由jvm在運作時建立的,用以表示未知類裡對應的成員。這樣你就可以使用constructor建立新的對象,用get()和set()方法讀取和修改與field對象關聯的字段,用invoke()方法調用與method對象關聯的方法。另外,還可以調用getfields(),getmethods()和getconstructors()等很便利的方法,以傳回表示字段,方法以及構造器的對象的數組。這樣,匿名對象的類資訊就能在運作時被完全确定下來,而在編譯時不需要知道任何事情。

其實,反射機制并沒有什麼神奇之處。當通過反射與一個未知類型的對象打交道時,jvm隻知道簡單的檢查這個對象,看它屬于哪個特定的類。在用它做其他事情之前,我們必須先加載這個類的class對象。是以,那個類的.class檔案對于jvm來說必須是可擷取的,要麼在本地機器上,要麼可以通過網絡可以獲得。對于反射機制而言,在編譯時不能取得.class檔案,隻能在運作時打開和檢查.class檔案。

3.1 擷取方法資訊

<code>package com.qunar.reflect;</code>

<code>public class reflectdemo {</code>

<code>public static void main(string[] args) {</code>

<code>// int的類類型</code>

<code>class class1 = int.class;</code>

<code>class class2 = string.class;</code>

<code>class class3 = double.class;</code>

<code>class class4 = double.class;</code>

<code>class class5 = void.class;</code>

<code>system.out.println("class1-&gt;" + class1.getname());</code>

<code>system.out.println("class2-&gt;" + class2.getname());</code>

<code>system.out.println("class3-&gt;" + class3.getname());</code>

<code>system.out.println("class4-&gt;" + class4.getname());</code>

<code>system.out.println("class5-&gt;" + class5.getname());</code>

運作結果:

class1-&gt;int

class2-&gt;java.lang.string

class3-&gt;double

class4-&gt;java.lang.double

class5-&gt;void

<code>// 隻列印簡單名稱(不包含包名稱)</code>

<code>system.out.println("class2-&gt;" + class2.getsimplename()); // string</code>

<code>/**</code>

<code>* 列印類成員方法資訊(public函數,包括父類繼承而來的)</code>

<code>* @param object</code>

<code>public static void printclasspublicfunction(object object){</code>

<code>// 擷取類的資訊,首先擷取類的類類型</code>

<code>// 傳遞的是哪個子類的對象 c 就是該子類的類類型</code>

<code>class c = object.getclass();</code>

<code>system.out.println("類的全稱是:" + c.getname());</code>

<code>// 一個成員方法就是一個method對象</code>

<code>// getmethods方法是擷取的是所有public的函數,包括父類繼承而來的</code>

<code>method[] methods = c.getmethods();</code>

<code>for (method method : methods) {</code>

<code>// 擷取方法傳回值類型的類類型</code>

<code>class returntype = method.getreturntype();</code>

<code>system.out.print(returntype.getname() + " ");</code>

<code>// 擷取方法的名稱</code>

<code>system.out.print(method.getname() + "(");</code>

<code>// 擷取方法參數</code>

<code>// 得到方法參數清單中類型的類類型</code>

<code>class[] paramtypes = method.getparametertypes();</code>

<code>int size = paramtypes.length;</code>

<code>for (int i = 0;i &lt; size;++i) {</code>

<code>if(i != 0){</code>

<code>system.out.print(",");</code>

<code>}//if</code>

<code>system.out.print(paramtypes[i].getname());</code>

<code>}//for</code>

<code>system.out.println(")");</code>

boolean startswith(java.lang.string)

boolean startswith(java.lang.string,int)

java.lang.charsequence subsequence(int,int)

java.lang.string substring(int,int)

java.lang.string substring(int)

[c tochararray()

java.lang.string tolowercase(java.util.locale)

java.lang.string tolowercase()

java.lang.string touppercase()

java.lang.string valueof([c)

java.lang.class getclass()

void notify()

void notifyall()

void wait(long)

void wait(long,int)

void wait()

....

3.2 擷取成員變量資訊

<code>* 列印類成員變量資訊</code>

<code>public static void printclassfiled(object object){</code>

<code>/* 成員變量也是對象,java.lang.reflect.field 類封裝了關于成員變量的操作</code>

<code>* getfields()方法擷取的是所有的public的成員變量的資訊</code>

<code>* getdeclaredfields()擷取的是該類自己聲明的成員變量的資訊</code>

<code>field[] fields = c.getdeclaredfields();</code>

<code>for (field field : fields) {</code>

<code>// 得到成員變量的類型的類類型</code>

<code>class fieldtype = field.gettype();</code>

<code>// 得到成員變量的類型</code>

<code>system.out.print(fieldtype.getname() + " ");</code>

<code>// 得到成員變量的名稱</code>

<code>system.out.println(field.getname());</code>

int min_value

int max_value

java.lang.class type

[c digits

[c digittens

[c digitones

[i sizetable

int value

int size

long serialversionuid

boolean $assertionsdisabled

3.3 擷取構造函數資訊

<code>* 列印類構造函數資訊</code>

<code>public static void printclassconstructor(object object){</code>

<code>/* 構造函數也是對象,java.lang.reflect.constructor 類封裝了關于構造函數的操作</code>

<code>* getconstructors()方法擷取的是所有的public的構造函數的資訊</code>

<code>* getdeclaredconstructors()擷取的是該類自己聲明的構造函數的資訊</code>

<code>constructor[] constructors = c.getconstructors();</code>

<code>for (constructor constructor : constructors) {</code>

<code>// 構造函數的名稱</code>

<code>system.out.print(constructor.getname() + "(");</code>

<code>// 擷取構造函數的參數清單,得到的是參數清單的類類型</code>

<code>class[] paramtypes = constructor.getparametertypes();</code>

<code>for(int i = 0;i &lt; size;++i){</code>

<code>// 得到參數名稱</code>

java.lang.string([b)

java.lang.string([b,int,int)

java.lang.string([b,java.nio.charset.charset)

java.lang.string([b,java.lang.string)

java.lang.string([b,int,int,java.nio.charset.charset)

java.lang.string(java.lang.stringbuilder)

java.lang.string(java.lang.stringbuffer)

java.lang.string([i,int,int)

java.lang.string([c,int,int)

java.lang.string([c)

java.lang.string(java.lang.string)

java.lang.string()

java.lang.string([b,int,int,java.lang.string)

java.lang.string([b,int)

java.lang.string([b,int,int,int)

3.4 方法的反射

如何擷取某個方法?方法的名稱和方法的參數清單才能唯一決定某個方法。

如何進行操作?通過method.invoke(對象,參數清單)

<code>import java.lang.reflect.invocationtargetexception;</code>

<code>import java.lang.reflect.method;</code>

<code>import com.qunar.bean.calculates;</code>

<code>calculates calculates = new calculates();</code>

<code>calculates.setnum1(20);</code>

<code>calculates.setnum2(40);</code>

<code>class c = calculates.getclass();</code>

<code>/* getmethod()方法擷取的是public的方法資訊</code>

<code>* getdeclaredmethod()擷取的是該類自己聲明的方法的資訊</code>

<code>// 擷取方法 名稱和參數清單共同決定</code>

<code>// method method = c.getdeclaredmethod("add", new class[]{int.class,int.class});</code>

<code>method method = c.getdeclaredmethod("add", int.class,int.class);</code>

<code>// 方法的反射</code>

<code>// 對于calculates.add(10,40)來說,方法的反射操作是用method方法調用 和 calculates.add(10,40)的效果一樣</code>

<code>// int result = (int)method.invoke(calculates, new object[]{10,40});</code>

<code>int result = (int)method.invoke(calculates, 10,40);</code>

<code>system.out.println(result);</code>

<code>// 對于沒有參數的方法</code>

<code>method method2 = c.getdeclaredmethod("print");</code>

<code>method2.invoke(calculates);</code>

<code>} catch (nosuchmethodexception e) {</code>

<code>} catch (securityexception e) {</code>

<code>} catch (illegalargumentexception e) {</code>

<code>} catch (invocationtargetexception e) {</code>