天天看點

Java文法糖--反射

1. 反射的概念

對于一個人來說,了解自己的能力、本事、特點,對于他去幹事創業來說,是很重要的。

同樣的,對于一門面向對象的語言來說,了解類(對象其實就是類的實作)本身也是重要的,可以在很多地方幫助程式更好的進行。

那麼類/對象本身包含那些内容呢,無非就是類名稱;父類;繼承的接口;類的屬性;類的方法,這些都屬于是類的資訊。

好的,那麼這些資訊程式員都知道啊,類的資訊在定義類的時候不是都寫的明明白白的嗎。但是反射的意義卻是:在程式跑起來之後可以使用代碼去擷取類的資訊。這個,沒有反射可辦不到。

Java是面向對象的,所有的東西都是有類别的。是以哦,類的資訊也是一種類型(就像使用者資訊可以用UserInfo類描述),類的資訊對應的Java類為Class類,注意不是關鍵字class哈。

舉個最常見的栗子:

public class ClassDemo {

public static void main(String[] args) {

 try {

  Class mysqlDriver=Class.forName("com.mysql.jdbc.Driver");

 } catch (ClassNotFoundException e) {

  e.printStackTrace();

 }

}

}

1

2

3

4

5

6

7

8

9

這裡Class.forName很明顯是Class類的一個static方法,這個方法的意思就是按類名(完整的帶包路徑的類名)傳回類對應的Class對象。因為forName的參數是可以随便寫的嘛,是以會抛出一個ClassNotFoundException。

Class.forName方法是在程式運作時按類名稱擷取類的資訊的方法,這就是反射機制。

2. 如何擷取類的Class對象

我們定義一個普通類Student,可以有三種方式擷取到Student的類型資訊:

package temp;
public class Student {
    String studentName;
    public String getStudentName(){
        return studentName;
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //方式1 利用類名稱
        Class class1 = Class.forName("temp.Student");  
        //方式2 利用類
        Class class2=Student.class;
        //方式3 利用對象
        Student student=new Student();
        Class class3=student.getClass();
    }
}
      

3. 通過類的Class對象擷取類的屬性和方法

擷取到Class(類的類型)之後,再擷取屬性和方法就簡單了,直接使用Class類封裝的方法即可。

getDeclaredFields():擷取類屬性

getDeclaredMethods():擷取類方法

使用一個完整的程式示範如下:

package temp;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Student {
    String studentName;
    public String getStudentName(){
        return studentName;
    }
    public static void main(String[] args) throws ClassNotFoundException {
        Class classStu=Student.class;
        Field[] fields = classStu.getDeclaredFields();
        for(Field field:fields){
            System.out.println("屬性類型:"+field.getType().getSimpleName()+",屬性名稱:"+field.getName());
        }
        Method[] methods=classStu.getDeclaredMethods();
        for(Method method:methods){
            System.out.println("方法名稱:"+method.getName()+",傳回類型"+method.getReturnType());
        }
    }
}

      

執行結果如下:

屬性類型:String,屬性名稱:studentName

方法名稱:main,傳回類型void

方法名稱:getStudentName,傳回類型class java.lang.String

可見,通過Class類封裝的方法,可以在程式運作時候直接擷取類的資訊。

4. 反射的意義

凡是都有正反兩個方面,先說不好的消息吧,用了反射,性能肯定是會降低的。注意此處的性能低,并不是說通過反射擷取類的資訊性能低,因為除了反射也沒有啥可以擷取類的資訊的機制了。

性能低是指通過反射調用方法性能低,看下面的例子,通過反射擷取到方法之後,可以将該方法應用到一個對象上實作該對象的方法調用。本來可以直接調用,反射之後再調用肯定效率要低的。

Class classStu=Student.class;

Student student=new Student();

Method methodGet=classStu.getDeclaredMethod("getStudentName");

//可以通過Method類的invoke方法調用類方法,當然必須得提供對象

String name=(String)methodGet.invoke(student);

System.out.println(name);

但是反射的正面意義還是光輝的,首先提供了一種了解類的資訊的手段,使程式運作編寫、運作更加自由靈活,充滿了更多可能性。

簡單的想,在将對象轉換為json時,鍵值對的鍵不就是對象的屬性名稱麼,用反射擷取對象的屬性名稱是多麼爽快的事情啊。