JAVA反射系列之 構造函數,方法,屬性反射詳解

一 前言

上篇博客我們講了 Class 類,也是爲本篇做鋪墊的。下面進入正文

1.1反射機制是什麼?

答:在程序運行狀態時,對於任意一個類,都能夠知道這個類的所有構造函數,方法和屬性;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

1.2爲什麼要用反射機制?反射機制優缺點。

爲什麼要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態編譯的概念,
靜態編譯:在編譯時確定類型,綁定對象,即通過。
動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以降低類之間的藕合性。

  • 優點:就是可以實現動態創建對象和編譯,體現出很大的靈活性。
  • 缺點:對性能有影響。反射相當於一系列解釋操作,通知jvm要做的事情,性能比直接的java代碼要慢很多。

1.3反射機制能做什麼?

  • 生成動態代理(下篇我們會說動態代理);
  • 插件化中用到了大量的反射;
  • 在運行時構造任意一個類的對象;
  • 在運行時判斷任意一個對象所屬的類;
  • 等等。

二 構造函數,方法,屬性反射詳解

2.1 構造函數反射

獲得構造函數的方法

    //根據指定參數獲得public構造器
    Constructor getConstructor(Class[] params);
    //獲得public的所有構造器
    Constructor[] getConstructors();
    //根據指定參數獲得public和非public的構造器
    Constructor getDeclaredConstructor(Class[] params);
    //獲得public的所有構造器 
    Constructor[] getDeclaredConstructors();

看這些方法如何使用,先來個Student類供我們反射使用

public class Student {

    private static String TAG = Student.class.getSimpleName();
    public int age;
    private String name;

    public Student() {
        age = 20;
        name = "小明";
    }

    public Student(int age, String name) {
        Log.e(TAG, "Student: " + "age " + age + " name " + name);
    }

    public void StudentA() {
        Log.e(TAG, "StudentA: ");
    }

    public void StudentA(int age) {
        Log.e(TAG, "StudentA: " + "age " + age);
    }

    public void StudentA(int age, String name) {
        Log.e(TAG, "StudentA: " + "age " + age + " name " + name);
    }
}
1. 獲得public的所有構造器Constructor[] getConstructors();使用如下
        //通過 包名+類名 獲取 Student類類型
        Class c = Class.forName("zhangqilu.com.plugin.Student");
        //獲得public的所有構造器
        Constructor[] constructors = c.getConstructors();
        for (Constructor con:constructors) {
            String constructorName = con.getName();
            System.out.print(constructorName+"(");
            //獲得構造函數的所有參數
            Class[] classType = con.getParameterTypes();
            for (int i = 0; i <classType.length ; i++) {
                if(i==classType.length-1){
                    System.out.print(classType[i].getName());
                }else{
                    System.out.print(classType[i].getName()+",");
                }
            }
            System.out.println(")");
        }

控制檯打印日誌如下:

03-08 19:02:21.051 17440-17440/zhangqilu.com.plugin I/System.out: zhangqilu.com.plugin.Student()
03-08 19:02:21.051 17440-17440/zhangqilu.com.plugin I/System.out: zhangqilu.com.plugin.Student(int,java.lang.String)

打印出2個構造函數,一個是沒有參數構造函數Student()
另一個是有2個參數(int和String類型)的構造函數 Student(int,java.lang.String)

2. 根據指定參數獲得public構造器Constructor getConstructor(Class[] params);

Class[] params 構造函數的參數類型 的 類類型
使用如下

//通過 包名+類名 獲取 Student類類型
            Class stuentClass = Class.forName("zhangqilu.com.plugin.Student");
//通過 Student類類型獲取 構造函數 int.class, String.class 構造函數的參數類型 的 類類型
            Constructor constructor = stuentClass.getConstructor(int.class, String.class);
//創建Student類實例  構造函數參數 age 100   name dog
            Object object = constructor.newInstance(100, "dog");

控制檯打印日誌如下:

03-08 19:54:13.029 25292-25292/? E/Student: Student: age 100 name dog

構造函數的反射主要就2種情況,1是獲取所有構造函數, 2是根據指定參數獲取構造函數。下面我們來看看方法的反射。

2.2方法反射

獲得類方法的方法
Method getMethod(String name, Class[] params),根據方法名,參數類型獲得方法

    //獲得所有的public方法包括父類繼承而來的
    Method[] getMethods();
    //根據方法名和參數類型,獲得public和非public的方法
    Method getDeclaredMethod(String name, Class[] params);
    Method[] getDeclaredMethods()//獲得所以的public和非public方法 ;
1.獲得所有的public方法包括父類繼承而來的Method[] getMethods();使用如下.
            Class c = Class.forName("zhangqilu.com.plugin.Student");//通過 包名+類名 獲取 Student類類型;
            Method[] methods = c.getMethods();//獲得所有的public方法 包括父類繼承而來的;
            for (int i = 0; i < methods.length; i++) {
                Class returnType = methods[i].getReturnType();//方法的返回值類型
                System.out.print(returnType.getName()+ " " );
                System.out.print(methods[i].getName()+ "(" );//獲得方法的名字
                Class[] paramTypes = methods[i].getParameterTypes();//方法所有參數
                for (int j = 0; j < paramTypes.length; j++) {
                    if(j==paramTypes.length-1){                       System.out.print(paramTypes[j].getName());
                    }else {                     System.out.print(paramTypes[j].getName()+",");
                    }
                }
                System.out.println(")" );//獲得方法的名字
            }

控制檯打印日誌如下

03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA()
03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA(int)
03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA(int,java.lang.String)
03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.Object access$super(zhangqilu.com.plugin.Student,java.lang.String,[Ljava.lang.Object;)
03-09 10:41:45.392 10495-10495/? I/System.out: boolean equals(java.lang.Object)
03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.Class getClass()
03-09 10:41:45.392 10495-10495/? I/System.out: int hashCode()
03-09 10:41:45.392 10495-10495/? I/System.out: void notify()
03-09 10:41:45.392 10495-10495/? I/System.out: void notifyAll()
03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.String toString()
03-09 10:41:45.392 10495-10495/? I/System.out: void wait()
03-09 10:41:45.392 10495-10495/? I/System.out: void wait(long)
03-09 10:41:45.392 10495-10495/? I/System.out: void wait(long,int)
2.根據方法名和參數類型,獲得public和非public的方法
Method getDeclaredMethod(String name, Class[] params);
參數含義:
name   方法名
Class[] params   方法的參數類型 的 類類型

我們還要看一個反射的重要方法

public Object invoke(Object obj,Object... args)

參數理解:
obj 反射方法的對象(調用誰的方法用誰的對象)
如果方法爲 靜態的 obj 可以爲null
args 用於方法調用的參數

體使用如下:

            Class studentClass = Class.forName("zhangqilu.com.plugin.Student");//通過 包名+類名 獲取 Student 類類型;
            Object object = studentClass.newInstance();//獲取Student 實例;          Method method = studentClass.getMethod("StudentA", int.class, String.class);//根據方法名和參數類型獲取方法實例;
method.invoke(object, 20, "zhangqilu");//反射執行方法

控制檯打印日誌如下

03-09 16:02:55.082 2372-2372/zhangqilu.com.plugin E/Student: StudentA: age 20 name zhangqilu

2.3 屬性反射

獲得類中屬性的方法

    //根據變量名得到相應的public變量
    Field getField(String name)
    //獲得類中所以public的方法
    Field[] getFields()
    //根據方法名獲得public和非public變量
    Field getDeclaredField(String name)
    //獲得類中所有的public和非public方法 
    Field[] getDeclaredFields()

屬性反射和構造函數和方法反射類似,我們只說

 Field getDeclaredField(String name)

使用。

            Class stuentClass = Class.forName("zhangqilu.com.plugin.Student");
            Object object = stuentClass.newInstance();
            Field field = stuentClass.getField("age");
            int age = (int) field.get(object);
            Log.e(TAG, "reflectionField: age " + age);
            Field field1 = stuentClass.getDeclaredField("name");
             /*
            Java代碼中,常常將一個類的成員變量置爲private
            在類的外面獲取此類的私有成員變量的value時,需要注意:
            將field.setAccessible(true);
             */
            field1.setAccessible(true);
            String name = (String) field1.get(object);
            Log.e(TAG, "reflectionField: name " + name);

控制檯打印日誌如下。

03-09 16:19:54.337 14194-14194/zhangqilu.com.plugin E/MainActivity: reflectionField: age 20
03-09 16:19:54.338 14194-14194/zhangqilu.com.plugin E/MainActivity: reflectionField: name 小明

反射就說到這裏,下一篇我們講代理(靜態代理和動態代理)。

發佈了47 篇原創文章 · 獲贊 41 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章