寫的不是很詳細,可能會有看不懂的地方,建議去慕課網的視頻:https://www.imooc.com/video/3735java
之前就學習過java的反射,可是後來一直沒有用過,如今回過頭來看了一下,並把知識點作了整理程序員
1)在面向對象的世界裏,萬事萬物皆對象。 類也是對象,類是java.lang.Class類的實例對象。 官方文檔是這麼解釋的There is a class named Class 2)Foo的實例對象 Foo foo1=new Foo(); //Foo類是java.lang.Class類的實例對象,也有構造方法(本地方法),可是不能使用new //三種表示方式 //第一種表示方式--->說明任何一個類都有一個隱含的靜態成員變量class Class c1=Foo.class; //第二種表達方式--->已經有該類的對象經過getClass()方法 Class c2=foo1.getClass(); //第三種表達方式 Class c3=Class.forName("com.Foo"); //經過c1 or c2 or c3(類類型)建立Foo的實例對象(須要用try catch包住) Foo foo=(Foo)c1.newInstance();//須要有無參數的構造方法
在這裏能夠看到Class的構造方法,是本地方法,只能由虛擬機建立,而且由c語言實現數組
c1,c2,c3表示了Foo類的類類型(class type)
一個類是Class類的一個實例對象(c1==c2==c3)返回true
建立實例對象:c1.newInstance();框架
這一部分使用ide工具是看不出來的,最好使用Sublime相似的工具,首先添加.java文件,後使用javac對文件進行編譯,使用java運行編譯後的文件看是否出錯 定義office類,靜態加載類 public class office(){ public static void main(String[] args){ if("word".equals(args[0])){ Word word=new Word(); } if("excel".equals(args[0])){ Excel excel=new Excel(); } } } javac office.java就會直接報錯,由於Word和Excel類沒有實現 new建立對象:靜態加載類,在編譯時刻就加載全部的【可能用到的類】。任何一個使用的類有問題,都不能經過編譯,都會報錯。 在上面的例子中用到了:new Word();new Excel();須要靜態加載Word、Excel類,編譯時刻就會對類Word和Excel進行加載,若是(任一)類文件中有錯誤就會編譯不經過。 定義office2類,動態加載類 public class office2(){ public static void main(String[] args){ if("Word".equals(args[0])){ Class class=Class.forName(args[0]); Word word=(Word)class.newInstace(); } if("Excel".equals(args[0])){ Class class=Class.forName(args[0]); Excel excel=(Excel)class.newInstace(); } } } 而且還有Word類 public class Word(){ public Word(){} } javac office2.java,編譯沒問題 java office2 Word,運行沒問題 java office2 Excel,運行出錯 Class.forName():動態加載類,運行時刻進行加載。 若是名稱爲args[0]的類不存在,編譯時刻沒問題,可是運行會報錯。這就是爲什麼有時候會出現編譯經過,運行報錯的緣由。 動態加載一個好處,就是能夠隨時增長鬚要編譯的類。例如沒有Excel類,只有Word類,也能夠運行,須要Excel類時再由程序員寫此類 (爲了能統一控制,Word類、Excel類須要繼承同一個父類或者繼承同一個接口)。 public Interface Micro(){} public class Word implements Micro(){} public class Excel implements Micro(){} public class Test(){ public static void main(String[] args){ Class class=Class.forName(args[0]); Micro micro=(Micro)class.newInstace(); //這裏的micro會根據args[0]的值來肯定是哪個實現類(子類)的對象啊 } }
new建立對象,編譯時刻(javac)加載類,Class.forName("");運行時刻(java)加載類ide
理解了爲何有時候會出現編譯經過,運行報錯的緣由。(由於使用了動態加載類)函數
public static void pringClassMessage(Object object) { //要獲取類的信息,首先要獲取類的類型 Class c = object.getClass(); //獲取類的名稱 System.out.println("類的名稱是:" + c.getName()); /* * Method類,方法對象 * 一個成員方法就是一個Method對象 * getMethods()方法獲取的是全部public函數,包括父類繼承而來的 * getDeclaredMethods()獲取的是全部該類本身聲明的方法,不問訪問權限 * */ Method[] ms = c.getMethods();//c.getDeclaredMethods(); for (int i = 0; i < ms.length; i++) { //獲得方法的返回值類型的類類型 Class returnType = ms[i].getReturnType(); System.out.println(returnType.getName()); //獲得方法名 System.out.println(ms[i].getName() + "("); //獲取參數類型-->獲得的是參數列表的類型的類類型 Class[] paramType = ms[i].getParameterTypes(); for (Class class1 : paramType) { System.out.println(class1.getName() + ","); } System.out.println(")"); } } }
java的方法也是類對象,是java.lang.refelect.Method的對象工具
經過下面兩個方法,能夠得到類類型是c1的類的方法數組學習
c1.getMethod();spa
c1.getDeclareMethod();3d
返回值的類類型
m[0].getReturnType();
參數的類類型數組
m[0].getParameterTypes();
Java反射機制——獲取成員變量 成員變量是java.lang.reflect.Field的對象 一、Field類封裝了關於成員變量的操做 二、Field[] fs = c.getFields()方法獲取全部public的成員變量Field[]信息 三、c.getDeclaredFields獲取的是該類本身聲明的成員變量信息 四、field.getType()得到成員類型的類類型 五、field.getName()得到成員的名稱
類的成員變量是java.lang.reflect.Field的對象
c1.getField();
c1.getDeclareField();
成員變量的類類型
f[0].getType();
成員變量的名稱
f[0].getName();
Java反射機制——獲取構造函數 構造函數是java.lang.Constructor類的對象 一、經過Class.getConstructor()得到Constructor[]全部公有構造方法信息 二、建議getDeclaredConstructors()獲取本身聲明的構造方法 三、Constructor.getName():String 四、Constructor.getParameterTypes():Class[]
方法的反射: 1.獲取A類中的print(int,int)方法: //要獲取一個方法就是獲取類的信息,獲取類的信息首先要獲取類的類類型 A a1=new A(); Class c= a1.getClass(); //獲取方法 由名稱和參數列表來決定,getMethod獲取的是public方法,getDelcaredMethod獲取本身聲明的方法 Method m =c.getMethod(methodName,paramtypes);//paramtypes能夠用數組的形式 表示new Class[]{int.class,int.class},也能夠直接列舉類類型 2.方法的反射操做:是用m對象來進行方法調用,和a1.print(10,20)調用的方法相同 m.invoke(a1,new Object[]{10,20}) Object o=m.invoke(對象名,參數);//方法若是沒有返回值返回null,若是有返回值返回具體值,參數可用數組的方式表示,也能夠直接列舉,沒有參數就不寫 public Class A{ public void print(){}; public void Print(Sting a,String b){} public void Print(int a,int b){}; } public Class B{ public static void main(String[] args){ A a1 = new A(); Class c= a1.getclass; Method getMet=c.getMethod("print",String.class,String.class);//忘了加引號 Object obj=getMet.invoke(a1,"df","df"); } }
獲取方法
c1.getMethod("方法名",Class[]);
調用方法
m.invoke(c1,參數);
Java反射機制——經過反射了解集合泛型的本質 1:反射的操做都是編譯以後的操做;就是運行階段 2:java中集合的泛型是防止錯誤輸入的;只在編譯階段有效,只要繞過編譯就無效啦 咱們能夠經過方法的反射來操做,繞過編譯 ArrayList list1=new ArrayList(); ArrayList<String> list2=new ArrayList<String>(); Class c1=list1.getClass(); Class c2=list2.getClass(); System.out.print(c1==c2); //true Method m=c2.getMethod("add",Object.class); m.invoke(list2,20); //向list2集合中添加一個int 型的值,繞過編譯 固然是不能直接foreach list2集合的,會報類型轉換錯誤
1:反射的操做都是編譯以後的操做
2:java中集合的泛型是防止錯誤輸入的;只在編譯階段有效,只要繞過編譯就無效啦,咱們能夠經過方法的反射來操做,繞過編譯
反射是運行階段處理的,繞過了編譯,因此好多東西編譯階段是不處理的
我的開發中反射用到的會比較少,具體會不會用也要看需求,功能主要就是根據一個String來獲得你要的實體對象,而後調用它包含的東西。
可是若是是要本身寫框架的話,那就會用得比較多了。