Java反射基礎-框架的靈魂

反射的概述

對於一個在運行狀態中的類,使用反射機制可以知道這個類的所有屬性和方法;對於任何一個對象,使用反射機制都可以調用它的任意一個方法和屬性。這種動態獲取信息以及動態調用對象方法的功能稱爲Java語言的反射機制。

Class類

Class類的實例表示正在運行的Java應用程序中的類和接口。也就是jvm中有N多的實例每個類都有該Class對象,甚至包括基本數據類型。
Class類沒有公共的構造方法。它是由java虛擬機以及調用類加載器中的defineClass方法自動構造的。

獲取class對象的三種方式

  1. ‘類的引用’.getClass()
  2. 類名.class
  3. Class.forName(“類的全路徑”)
package com.xiaopeng.reflect;


/**
 * 獲取 Class 文件的三種方式
 * 1、'類的引用'.getClass()
 * 2、類.class
 * 3、Class.forName('classPath');
 * ----------------------------------
 * 在運行期間,一個類,只有一個Class對象產生
 */
public class Fanshe {

    public static void main(String[] args) {

        Student student = new Student();

        Class stuClazz = student.getClass();

        //輸出class文件的全路徑
        System.out.println("類Student-->" + stuClazz.getName());

        //判斷兩個class文件是否相同
        Class stuClazz2 = Student.class;

        System.out.println(stuClazz == stuClazz2);

        try {
            Class stuClass3 = Class.forName("com.xiaopeng.reflect.Student");

            System.out.println(stuClass3 == stuClazz2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

在程序運行期間,一個類只產生一個Class對象。一般常用的第三種方法來獲取類的Class對象。
1. 第一種方式已經獲取了對象的引用,不需要獲取Class對象
2. 第二種方式需要導入類的全路徑,程序的依賴性強
3. 傳入一個字符串,獲取類的Class對象,可以使用配置文件配置該字符串

獲取構造方法並調用

//獲取所有公有的構造方法
Constructor[] consArray = clazz.getConstructors();
//獲取所有的構造方法(private/protected/public/..)
Constructor[] consArray = clazz.getDeclaredConstructors();
//獲取公有無參數的構造方法,形參表示構造方法中參數的類型String.class/int.class
Constructor con = clazz.getConstructor(null);
//調用類的構造方法
con = clazz.getDeclaredConstructor(int.class); //獲取構造方法
con.setAccessible(true); //如果構造方法是私有的,那麼需要修改爲"允許訪問"
Object o = con.newInstance(24); //通過構造方法創建對象的引用

獲取成員變量並調用

//獲取所有公有的字段
Field[] fieldArray = clazz.getFields();
//獲取所有成員變量
Field[] fieldArray = clazz.getDeclaredFields();
//使用成員變量
Object obj = clazz.getConstructor().newInstance(); //獲取對象的引用
Field f = clazz.getField("address");   //獲取對象的address成員變量
f.setAccessible(true);     //若是 private 屬性,需要設置訪問權限
f.set(obj,"shanxi");       //將address屬性賦值爲shanxi
People p = (People)obj;    //類型轉換

獲取成員方法並調用

//獲取所有公有方法
Method[] methodArray = clazz.getMethods();
//獲取所有成員方法
Method[] methodArray = clazz.getDeclaredMethods();
//獲取某個特定的方法,並調用方法
People p = clazz.getConstructor().newInstance();   //獲取對象的引用
Method m = clazz.getMethod("sayHello",String.class,int.class); //private String sayHello(String message,int times)
m.setAccessible(true);   //私有成員方法需要設置訪問權限
Object o = m.invoke(p,"你好"20);  //調用sayHello方法,並獲取輸出

反射獲取並調用main方法

Method mainMethod = clazz.getMethod("main",String[].class);
/**
 * 因爲main方法是靜態方法,所以對象的引用傳入null即可
 **/
mainMethod.invoke(null,(Object)new String[]{"q","w","e"})

使用泛型越過泛型檢查

jdk1.5 開始,引入的泛型的新特性,泛型用在編譯期,編譯過後泛型會被檫除掉。所以可以通過反射越過泛型檢查。

public static void main(String[] args){

        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("aaa");
        arrayList.add("bbb");
        //arrayList.add(100);

        Class clazz = arrayList.getClass();
        try {
            Method m = clazz.getMethod("add",Object.class);

            m.invoke(arrayList,100);

        } catch (Exception e) {
            e.printStackTrace();
        }

        for(Object o : arrayList){
            System.out.println(o);
        }
    }

Java的反射這麼靈活,無非是將原來需要在“編譯時”必須要做的事推遲到了“運行時”,而方式也由原來的對象變成了可以靈活配置的字符串。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章