1. 程式人生 > >詳述獲取位元組碼檔案及其內容的方法

詳述獲取位元組碼檔案及其內容的方法

1 簡述

Java 的反射機制是指:

  • 在執行狀態中,對任意一個類(class檔案),都能知道這個類的所有屬性和方法;對任意一個物件,都能呼叫這個物件的方法和屬性

簡單點說,這種動態的獲取資訊和動態的呼叫物件的方法的功能就是 Java 的反射機制。利用 Java 的反射機制,我們可以很容易的獲取類的詳細資訊,如建構函式、成員變數和成員函式等。

2 獲取位元組碼檔案

首先,構造一個實體類:

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午5:15
 * @Description Person Entity
 */
public class
Person {
private String name; private int age; public Person() { System.out.println("Person run"); } public Person(String name, int age) { this.name = name; this.age = age; System.out.println("Person param run ... " + this.name + " is " + this.age + " years old!"
); } public void showInfo(String name, int age){ this.name = name; this.age = age; System.out.println("Show Peron Info : " + this.name + " is " + this.age + " years old!"); } public void playBadminton(){ System.out.println("Let's play badminton, go go go..."
); } }

接下來,以 Person 類為例,演示獲取位元組碼檔案的 3 種方式:

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午5:23
 * @Description Get class file
 */
public class GetClassFile {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("第 1 種獲取方式:");
        getClassObject_1();
        System.out.println("第 2 種獲取方式:");
        getClassObject_2();
        System.out.println("第 3 種獲取方式:");
        getClassObject_3();
    }

    /**
     * 利用 Object 類中的 getClass 方法
     * 用這個方法時,必須明確具體的類,並建立物件
     * 比較麻煩
     */
    public static void getClassObject_1() {
        Person p = new Person();
        Class clazz = p.getClass();
        Person p1 = new Person("Charies",18);
        Class clazz1 = p1.getClass();
        System.out.println(clazz == clazz1);
    }

    /**
     * 任何資料型別都具備一個靜態屬性
     * 通過 .class 來獲取對應的 Class 物件
     * 擴充套件性較差
     */
    public static void getClassObject_2() {
        Class clazz = Person.class;
        Class clazz1 = Person.class;
        System.out.println(clazz == clazz1);
    }

    /**
     * 通過給定的類的字串名稱就可以獲取該類的位元組碼檔案,更利於擴充套件
     * 可以用 Class 類中的 forName() 方法來完成
     */
    public static void getClassObject_3() throws ClassNotFoundException {
        // 包名一定要寫全,否則會報 java.lang.ClassNotFoundException 異常
        String className = "Person";
        Class clazz = Class.forName(className);
        System.out.println(clazz);
    }
}

執行上述程式碼,結果如下圖所示:

class

3 獲取位元組碼檔案的內容

3.1 獲取建構函式

import java.lang.reflect.Constructor;

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午6:07
 * @Description Get class constructor
 */
public class GetClassConstructor {
    public static void main(String[] args) throws Exception {
        createNewObject_1();
        createNewObject_2();
    }

    /**
     * 獲取預設建構函式
     */
    public static void createNewObject_1() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String name = "Person";
        // 尋找該名稱類檔案,並加進記憶體,產生 Class 物件
        Class clazz = Class.forName(name);
        // 產生該類的例項物件(空參)
        Object obj = clazz.newInstance();
    }

    /**
     * 獲取帶引數的建構函式
     */
    public static void createNewObject_2() throws Exception {
        /**
         *  當獲取指定名稱對應類中的實體物件時,而且該物件的初始化不適用空參的建構函式
         *  可以先通過該類的位元組碼檔案物件,獲取空參的建構函式
         *  該方法為:getConstructor(parameterTypes)
         */

        // 包名一定要寫全,否則會報 java.lang.ClassNotFoundException 異常
        String name = "Person";
        // 找尋該名稱類檔案,並加進記憶體,產生 Class 物件
        Class clazz = Class.forName(name);
        // 獲取指定的建構函式物件
        Constructor constructor = clazz.getConstructor(String.class, int.class);
        // 通過該構造器物件的 newInstance 方法進行物件的初始化
        constructor.newInstance("Charies", 18);
    }
}

3.2 獲取成員變數

import java.lang.reflect.Field;

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午6:15
 * @Description Get class field
 */
public class GetClassField {
    public static void main(String[] args) throws Exception {
        getField();
    }

    /**
     * 獲取位元組碼檔案中的成員變數
     */
    public static void getField() throws Exception {
        Class clazz = Class.forName("Person");
        Field field = null;
        // 獲取本類欄位,包含私有
        field = clazz.getDeclaredField("age");
        // 對私有欄位的訪問取消許可權檢查,可稱之為暴力訪問
        field.setAccessible(true);
        Object obj = clazz.newInstance();
        field.set(obj, Integer.valueOf(18));
        Object o = field.get(obj);
        System.out.println(o);
    }
}

3.3 獲取成員函式

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午6:22
 * @Description Get class method
 */
public class GetClassMethod {
    public static void main(String[] args) throws Exception {
        System.out.println("第 1 個方法:");
        getMethod_1();
        // System.out.println("第 2 個方法:");
        // getMethod_2();
        // System.out.println("第 3 個方法:");
        // getMethod_3();
    }

    /**
     * 獲取指定 Class 中的公有函式
     */
    public static void getMethod_1() throws Exception {
        Class clazz = Class.forName("Person");

        // 獲取的都是類中的公有方法
        Method[] methods = clazz.getMethods();

        // 獲取本類中的所有方法
        methods = clazz.getDeclaredMethods();
        Method[] var5 = methods;
        int var4 = methods.length;

        for (int var3 = 0; var3 < var4; ++var3) {
            Method method = var5[var3];
            System.out.println(method);
        }
    }

    /**
     * 獲取指定 Class 中的空參函式
     */
    public static void getMethod_2() throws Exception {
        Class clazz = Class.forName("Person");
        // 獲取空引數的方法
        Method method = clazz.getMethod("playBadminton");
        Constructor constructor = clazz.getConstructor(new Class[]{String.class, Integer.TYPE});
        Object obj = constructor.newInstance(new Object[]{"Charies", Integer.valueOf(18)});
        method.invoke(obj, (Object[]) null);
    }

    /**
     * Integer.TYPE 等價於 int.class
     */
    public static void getMethod_3() throws Exception {
        Class clazz = Class.forName("Person");
        Method method = clazz.getMethod("showInfo", new Class[]{String.class, Integer.TYPE});
        Object obj = clazz.newInstance();
        method.invoke(obj, new Object[]{"Charies", Integer.valueOf(18)});
    }
}