Java的反射機制

來源:互聯網
上載者:User

標籤:java   反射   class   reflect   

前言


反射提供了一種動態功能,這種動態功能非常強大。它主要體現在通過反射相關的API,就可以知道一個陌生


的Java類的所有資訊,包括屬性、方法、構造器等。而且元素完全可以在運行時動態進行建立或調用,而不必在


JVM運行時就進行確定。通過查閱相關資料,進行了整理,本篇也是基於下面文章進行擴充。


       《http://blog.csdn.net/mark_yangs/article/details/47427037》             

           

反射的原理是什麼


嚴格意義上來講,Java並不是動態語言,它並沒有Perl和Python那樣靈活。但是,Java的反射機制卻讓它顯得動


態起來。


一般情況下,如果想產生這個類的對象時,運行這個程式的JVM會確認這個類的Class對象是否已經載入。如果


尚未載入,JVM就會根據類名尋找.class檔案,並將其載入,一旦這個類的Class對象被載入記憶體,它就可以被用來創


建這個類的所有對象。


另外,對於一個未知類型的引用來說,通常會採用強制類型轉換的形式來得到開發人員想要的類型引用,如果執行


了一個錯誤的類型轉換,就會拋出一個ClassCastException異常。


  在以上兩個過程中,Class類一直都在起作用。因為Class類執行個體包含的是一個Java類的全部資訊,包括類名、方


法、屬性等。換句話來說,也就是Class對象就是代表一個類的類。


Java用Class類來代表了所有的類,方便了開發人員掌控類資訊。通過Class,開發人員可以得到屬性、方法、構造


器、修飾符等資訊。在動態擷取這些資訊以後,開發人員就可以用該Class建立執行個體、調用任何方法、訪問任何屬性


等操作,這些也是反射的主要用途。


反射機制相關的API主要集中在java.lang.reflect包下面,開發人員也就是利用該包下面的介面和類進行相關的反射


開發。大多數的架構,如Struts、Hibernate和Spring,都會頻繁地使用反射API來完成它們動態功能。


Class類的含義和作用是什麼


Class類在反射機制中起到了非常關鍵的作用,它是開發人員進行反射開發的入口。從上面可以知道Class是用來記


錄一個類的各種資訊,它伴隨著類的載入而 建立。那麼,類會在什麼時候被載入到JVM中呢?概括來說,一個普通的


Java類,會在以下幾種情況,被載入到JVM中。


(1)需要使用該類建立對象。如下代碼就會導致Stundent類被載入到JVM類中:


Student mStudent=new Student();

(2)訪問該類的靜態成員,執行個體代碼如下:


public class Student {static int count=2;}

public class Main {public static void main(String[] args) {System.out.println(Student.count);}}

(3)使用Class類的靜態forName()方法,動態地載入一個指定類名的類。如果類未找到,則拋出


ClassNotFoundException異常,執行個體代碼如下:


public class Main {public static void main(String[] args) throws ClassNotFoundException {Class clazz=Class.forName("com.example.bill.Student");}}


不管通過什麼樣的形式,類一旦被載入進入JVM以後,就會為它建立一個Class類的執行個體對象。那麼,開發人員又


該如何得到這個Class對象呢?概括來說,要得到一個類的Class對象,可以通過以下幾種途徑。


(1)Class的forName()方法的返回值就是Class類型,也就是動態匯入類的Class對象的引用。forName()方法的完


整定義如下:


public static Class<?> forName(String className) throws ClassNotFoundException


(2)每個類都會有一個名稱為Class的靜態屬性,通過它也是可以擷取到Class對象的,執行個體代碼如下:


Class<Student> clazz=Student.class;

(3)Object類中有一個名為getClass的成員方法,它返回的是對象的運行時類的Class對象。因為Object類是所有


類的父類,所以,所有的對象都可以使用該方法得到它運行時類的Class對象,執行個體代碼如下:


public class Main {public static void main(String[] args) throws ClassNotFoundException {Student mStudent=new Student();Class<Student> clazz=(Class<Student>) mStudent.getClass();}}

擷取到Class對象以後,就可以通過調用它的一些成員方法來擷取它所代表的類的屬性、方法、修飾符等資訊,


以及調用newInstance()方法來建立新的執行個體對象,還有其他一些功能方法。


如何操作類的成員變數


Field類,代表的是類的屬性(欄位),也被稱為成員變數。反射可以擷取到它的對象,Field對象通過Class類的


getDeclaredField()或getDeclaredFields方法擷取到,處於java.lang.reflect包下。Field提供有關類或介面的單個欄位


的資訊,以及對它的動態存取權限,反射的欄位可能是一個靜態欄位或執行個體的欄位。


Field的方法主要分為兩個類,即getXXX和setXXX。其中getXXX是用於擷取某個對象的該欄位的值,並且有一


定的類型規定,例如,getFloat(),而setXXX則是用於設定值,它們一般有兩個參數,一個是對象引用,另一個則是


需要設定的值。


以下為一個Field的使用樣本,通過反射來比較兩個對象的大小:


public class FieldTestClass {public String name;public int age;public FieldTestClass(String name,int age){super();this.name=name;this.age=age;}}


public class Main {public static void main(String[] args) throws ClassNotFoundException {FieldTestClass obj1=new FieldTestClass("bill1",100);FieldTestClass obj2=new FieldTestClass("bill2", 200);System.out.println(compare(obj1, obj2).name);}private static FieldTestClass compare(FieldTestClass obj1,FieldTestClass obj2){try {Field field1=obj1.getClass().getDeclaredField("age");Field field2=obj2.getClass().getDeclaredField("age");int val1=(Integer)field1.get(obj1);int val2=(Integer)field2.get(obj2);if(val1>val2){return obj1;}else{return obj2;}} catch (NoSuchFieldException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}}

以上代碼輸出結果為:bill2


值得注意的是,如果我們將FieldTestClass中的age設定成private,也就是私人屬性時,程式會報


IllegalAccessException異常。



如何操作類的方法


Method類,代表的是類的方法。與Field類似,反射可以擷取到它的對象,使用它的方式則是動態調用,Method


對象通過Class類的getMethod()或getMethods()方法擷取到,也處於java.lang.reflect包下,Method提供關於類或介面


中的某個方法(以及如何訪問該方法)的資訊,所反映的方法可能是類方法或執行個體方法(包括抽象方法在內)。


Method類中使用最多的方法是invoke(),它的含義就是方法調用。它的第一個參數為Class所代表的類的一個執行個體


對象,以後則是一個不定長的Object類型的參數列表,它是Method對象所代表的方法需要的參數列表。


以下為一個Method的使用執行個體,通過命令列參數來實現方法的動態調用:


public class MethodTestClass {public void m1(){System.out.println("m1.....");}public void m2(){System.out.println("m2.....");}}

public class CallMethodTest {public static void main(String[] args) {args = new String[] { "m1" };String methodName = args[0];if (methodName != null) {Class<MethodTestClass> clazz = MethodTestClass.class;try {Method m = clazz.getDeclaredMethod(methodName);if (m != null) {MethodTestClass obj = clazz.newInstance();m.invoke(obj);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}}

以上代碼輸出結果:m1.....


注意如果指定的方法名不存在,程式會報NoSuchMethodException異常;如果將方法的許可權設定成private,也就是私


有屬性時,程式會報IllegalAccessException異常。


如何利用反射機制訪問類的私人成員


根據Java的文法規則,類的私人成員(包括私人的成員變數和方法)只能被內部的方法所訪問。但是,通過反射


機制,卻可以訪問一個類的所有成員,包括私人成員在內。


如果開發人員在開發反射機製程序的時候,對待私人成員像公有成員一樣,那就會遇到一個異常的拋出,以下程式


可以訪問私人成員:

public class PrivateTestClass {private String field;public PrivateTestClass(String field){super();this.field=field;}}

public class PrivateTest {public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {PrivateTestClass obj=new PrivateTestClass("bill");Class clazz=obj.getClass();Field f=clazz.getDeclaredField("field");f.setAccessible(true);//訪問性設定成trueSystem.out.println(f.get(obj));}}


程式輸出結果:bill


從以上代碼來看,私人的成員變數field是可以被成功訪問的。其中比較關鍵一行代碼就是調用Field的


setAccessible()方法,讓field屬性變得可以訪問。



-------------------------------------------------------------------------------------------------------------------------------------------------------

轉載請註明出處:http://blog.csdn.net/hai_qing_xu_kong/article/details/47614679情緒控



著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Java的反射機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.