標籤:ram generate zh-cn modifier param 利用 cep == 時間
最近學習中遇到反射機制,可是老師只是輕描淡寫的解釋了一通,還是自己查資料補充一下。
Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態擷取的資訊以及動態調用對象的方法的功能稱為Java語言的反射機制。
一、Class類
1、Class是一個類,一個描述類的類(也就是描述類本身),封裝了描述方法的Method,描述欄位的Filed,描述構造器的Constructor等屬性
2、對象照鏡子後(反射)可以得到的資訊:某個類的資料成員名、方法和構造器、某個類到底實現了哪些介面。
3、對於每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。
一個 Class 對象包含了特定某個類的有關資訊。換句話說:任何類都是Class類的執行個體對象
4、Class 對象只能由系統建立對象
5、一個類在 JVM 中只會有一個Class執行個體
二、反射機制
反射是Java中一種強大的工具,能夠使我們很方便的建立靈活的代碼,這些代碼可以再運行時裝配,無需在組件之間進行原始碼連結。
作用:
- 在運行時判斷任意一個對象所屬的類;
- 在運行時擷取類的對象;
- 在運行時訪問java對象的屬性,方法,構造方法等。
反射的特點:
為什麼要用反射機制?直接建立對象不就可以了嗎,這就涉及到了動態與靜態概念。
靜態編譯:在編譯時間確定類型,綁定對象,即通過。
動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以降低類之間的藕合性
反射機制的優點:可以實現動態建立對象和編譯,體現出很大的靈活性(特別是在J2EE的開發中它的靈活性就表現的十分明顯)。通過反射機制我們可以獲得類的各種內容,進行了反編譯。對於JAVA這種先編譯再啟動並執行語言來說,反射機制可以使代碼更加靈活,更加容易實現物件導向。
舉例:一個大型的軟體,當程式編譯後,發布了,都會在後期不斷的更新以完善整個程式,我們不可能要使用者把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟體肯定是沒有多少人用的。採用靜態話,需要把整個程式重新編譯一次才可以實現功能的更新,而採用反射機制的話,它就可以不用卸載,只需要在運行時才動態建立和編譯,就可以實現該功能。 想一下,王者榮耀每次出新英雄或者出新皮膚的時候都會有更新,使用者在更新的時候知只是下載一個小的程式包進行安裝,而不用重新安裝整個王者榮耀遊戲,這就是採用動態編譯的例子。
反射機制的缺點:對效能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它 滿足我們的要求。這類操作總是慢於只直接執行相同的操作。
三、Class中實現反射機制的類
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
四、反射機制擷取類有三種方法
在利用反射擷取類的對象,對象的屬性,方法,構造方法等的時候都需要建立類的類類型
package com.neuedu.reflect;/* * 項目名稱:Java-Reflect * @author:wzc* @date 建立時間:2017年8月28日 下午8:41:29* @Description:擷取類的類類型* @parameter * */public class JavaDemo1 { public static void main(String[] args) {//Food的執行個體對象如何表示 Food food1=new Food(); /* * Food這個類也是一個執行個體對象,Class類的執行個體對象 * 任何一個類都是Class的執行個體對象,三種表示方式 * 第一種表達方式--->實際上在告訴我們任何一個類都有一個隱含的靜態成員class */ Class class1=Food.class; //第二種表示方式,已知該類的對象getClass Class class2=food1.getClass(); /* * c1,c2表示了Food類的類類型(class type) * 任何類都是class類的執行個體對象 * c1 c2都代表了Food的類類型,一個類只可能是Class類的一個執行個體對象 */ System.out.println(class1==class2); //第三種表達方式 Class class3=null; try {class3=Class.forName("com.neuedu.reflect.Food");} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(class2==class3); }//建立一個Food類class Food{public void print(){System.out.println("hello Food");}}
五、建立對象
擷取類的類類型以後我們就可以利用類類型建立該類的對象
package com.neuedu.reflect;/* * 項目名稱:Java-Reflect * @author:wzc* @date 建立時間:2017年8月28日 下午8:41:29* @Description:擷取類的類類型* @parameter * */public class JavaDemo1 { public static void main(String[] args) {//Food的執行個體對象如何表示 Food food1=new Food(); /* * Food這個類也是一個執行個體對象,Class類的執行個體對象 * 任何一個類都是Class的執行個體對象,三種表示方式 * 第一種表達方式--->實際上在告訴我們任何一個類都有一個隱含的靜態成員class */ Class class1=Food.class; //第二種表示方式,已知該類的對象getClass Class class2=food1.getClass(); /* * c1,c2表示了Food類的類類型(class type) * 任何類都是class類的執行個體對象 * c1 c2都代表了Food的類類型,一個類只可能是Class類的一個執行個體對象 */ System.out.println(class1==class2); //第三種表達方式 Class class3=null; try {class3=Class.forName("com.neuedu.reflect.Food");} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(class2==class3); //我們可以通過類的類類型建立類的對象執行個體 try {Food food2 = (Food) class1.newInstance();food2.print(); } catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}//建立一個Food類class Food{public void print(){System.out.println("hello Food");}}
六、擷取類的相關資訊: 類名,方法名,方法的傳回值類型,方法的參數列表
package com.neuedu.Uttil;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;/* * 項目名稱:Java-Reflect * @author:wzc* @date 建立時間:2017年8月29日 下午1:22:15* @Description: 1.利用反射列印類的資訊* 2.利用反射列印類的成員變數* 3.利用反射列印類的構造方法* @parameter * */public class Uttil {/* * 列印類的資訊,列印類的傳回值類型,類類名,參數列表 * * */public static void PrintClass(Object obj){Class cInt=obj.getClass();System.out.println("類的名稱:"+cInt.getName());/* * Method類,方法對象 * 一個成員方法就是一個Method對象 * getMethods()方法擷取的是所有的public的函數,包括父類繼承而來的 * getDeclaredMethods()擷取的是所有該類自己聲明的方法, * * */Method[] ms=cInt.getMethods();System.out.println("[類的傳回值類型],[類的名稱],[類的參數列表]");for (int i = 0; i < ms.length; i++) {//得到方法的傳回值類型的類類型Class returnType=ms[i].getReturnType();System.out.print(returnType.getName()+" ");//得到方法的名稱System.out.print(ms[i].getName()+"(");//擷取參數類型Class [] paramTypes=ms[i].getParameterTypes();for (Class class1 : paramTypes) {System.out.print(class1.getName()+",");}System.out.println(")");}}}
測試一下:
public class JunitTest {@Testpublic void test() {String string="hello";//Uttil.PrintClass(string);}}
執行結果:
七、擷取類的屬性
/* * 成員變數也是對象 * java.lang.reflect.Field; * Filed類封裝了關於成員變數的操作 * getFields()方法擷取的是所有的public的成員變數的資訊 * getDeclaredFields擷取的是該類自己聲明的成員變數的資訊 * * * */public static void printFieldInfo(Object obj) {//擷取類的成員變數Class class1=obj.getClass();Field[] fields=class1.getDeclaredFields();for (Field field : fields) {//得到成員變數的類型的類類型//得到成員變數的類型名Class fieldType=field.getType();String typeName=fieldType.getName();//得到成員變數的名稱String fieldName=field.getName();System.out.println(typeName+" "+fieldName);}}
測試一下:
@Testpublic void test() {Uttil.printFieldInfo(new Integer(1));}
結果:
八、擷取類的構造方法
/* * 列印對象的建構函式 * */public static void printConMessage(Object obj){ Class class1=obj.getClass(); /* * 建構函式也是對象 * java.lang.Contructor中封裝了建構函式的資訊 * getConstructors擷取所有的public的建構函式 * getDeclaredContructors得到所有的建構函式 * * */ Constructor[] ct=class1.getConstructors(); for (Constructor constructor : ct) {System.out.print(constructor.getName()+"(");//擷取建構函式的參數列表--->得到的是參數列表的類類型Class[] paramTypes=constructor.getParameterTypes();for (Class class2 : paramTypes) {System.out.print(class2.getName());}System.out.println(")");}}
測試一下:
@Testpublic void test() {String string="hello";Uttil.printConMessage(string);}
結果:
九、通過反射來執行對象的方法
package com.neuedu.reflect;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/* * 項目名稱:Java-Reflect * @author:wzc* @date 建立時間:2017年8月29日 下午6:45:21* @Description:通過反射執行類的方法* * @parameter * */public class RunMethod { public static void main(String[] args) { Student student=new Student("張三", 25); //1.要擷取方法,首先要擷取該方法的類類型, Class stuClass = student.getClass(); /* * 2.擷取方法、名稱和參數列表 * getMethod擷取的是public方法 * getDelcaredMethod自己聲明的方法 */ try {//stuClass.getMethod("getName",new Class[]{})//stuClass.getMethod("getName"); Method m1=stuClass.getMethod("getName", null);//3.方法的反射操作-----以前:student.getName(); //m1.invoke(obj,args..); //方法的反射操作是用m1對象來進行方法的調用 //方法如果沒有傳回值返回null,有傳回值返回具體的傳回值,並轉換成Object m1.invoke(student); System.out.println("=============="); m1=stuClass.getMethod("getAge", null); Object object=m1.invoke(student, null); System.out.println("=============="); //m1=stuClass.getMethod("getAge", int.class); m1=stuClass.getMethod("getAge", new Class[]{int.class}); m1.invoke(student, 2); } catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}//student類class Student{private String name;private int age;public Student(){}public Student(String name,int age){this.name=name;this.age=age;}//無參數方法public void getName(){ System.out.println("name:"+name);}//無參數方法public void getAge(){System.out.println("age:"+age);}//有參數的方法public void getAge(int num){System.out.println(num+"年前age:"+(age-num));}public void studentIn(){System.out.println("name:"+name+",age:"+age);}}
今天只是記錄一些反射最基礎的理論,之後會在寫一些反射的應用,只有應用了才能更好的理解反射的概念。
Java反射機制