何時Java反射

寫的不是很詳細,可能會有看不懂的地方,建議去慕課網的視頻:https://www.imooc.com/video/3735java

之前就學習過java的反射,可是後來一直沒有用過,如今回過頭來看了一下,並把知識點作了整理程序員

  • Class類

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();框架

  • Java 動態加載類

這一部分使用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

理解了爲何有時候會出現編譯經過,運行報錯的緣由。(由於使用了動態加載類)函數

  •  Java 獲取方法信息

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反射機制——獲取成員變量
成員變量是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反射機制——獲取構造函數
構造函數是java.lang.Constructor類的對象
一、經過Class.getConstructor()得到Constructor[]全部公有構造方法信息
二、建議getDeclaredConstructors()獲取本身聲明的構造方法
三、Constructor.getName():String
四、Constructor.getParameterTypes():Class[]
  •  Java 方法反射的基本操做

方法的反射:
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 經過反射了解集合泛型的本質

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來獲得你要的實體對象,而後調用它包含的東西。

可是若是是要本身寫框架的話,那就會用得比較多了。

相關文章
相關標籤/搜索