Java反射使用總結

一、概述

反射:指程序可以訪問,檢測和修改它本身狀態或行爲的一種能力,並能根據自身行爲的狀態和結果,調整或修改應用所描述行爲的狀態和相關的語義。也就是可以獲取正在運行的Java對象。

反射作爲Java中一個強大的工具,不僅可以很方便創建靈活的代碼,而且對一些其他第三方代碼可以進行增強。
其主要功能主要有:
1、可以判斷運行時對象所屬的類
2、可以判斷運行時對象所擁有的成員屬性和方法
3、生成動態代理

光看概念有些晦澀,我們先說一個簡單的應用反射的例子:

public class Item {
    private String id;
    private String name;
    private double price;

    public Item(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public String getId() {   return id; }
    public String getName() {  return name; }
    public double getPrice() { return price; }
}

上面這部分代碼不管出於什麼目的,其成員屬性只在new對象時接收,其他情況一律修改不了。我們可以通過反射來修改類的私有屬性。

public static void main(String[] args) throws Exception {
     Item item = new Item("1", "a", 1.0);
     Field field = item.getClass().getDeclaredField("id");
     field.setAccessible(true);
     field.set(item, "2");
     System.out.println(item.getId());  // 2
    }

運行可以發現,我們已經把其對象的id值更新到了2。

二、具體功能實現

1、獲取類並創建其對象:反射中獲取類通常有三種方法

Class clz1 = Class.forName("java.lang.String"); // 1.通過包和類名
Class clz2 = String.class;  // 2.直接通過類名

String str = new String();
Class clz3 = str.getClass(); // 3.根據對象(運行時類)

clz1.newInstance();
clz2.newInstance();
其他方法名 含義
getEnclosingClass() 返回底層類的立即封閉類
getDeclaredClasses() 返回 Class 對象的一個數組,這些對象反映聲明爲此 Class 對象所表示的類的成員的所有類和接口
getDeclaringClass() 如果此 Class 對象所表示的類或接口是另一個類的成員,則返回的 Class 對象表示該對象的聲明類

2、獲取類的屬性

方法名 含義
getFields() 獲取類的所有public屬性,包括其父類
getField() 獲取某一個屬性
getDeclaredFields() 獲取類的所有聲明的字段,不包括父類
getDeclaredField() 獲取某一個屬性

3、獲取類的方法

方法名 含義
getMethods() 獲取類的所有public方法,包括其父類
getMethod() 獲取某一個方法
getDeclaredMethods() 獲取類的所有聲明的方法,不包括父類
getDeclaredMethod() 獲取某一個方法
getConstructors() 獲取訪問權限是public的所有構造方法
getConstructor() 獲取某一個構造方法
getDeclaredConstructors() 獲取類的所有構造方法
getConstructors() 獲取某一個構造方法

4、總結

  • 反射裏的Class, Field, Method, Constructor必須結合對象使用,除非是靜態的。
  • 獲取非public對象須用類似getDeclaredMethod()而不是getMethod()。
  • Field和Method都能設置accessible(true),之後能訪問到私有權限。

三、一個簡單的例子

下面是一個Person類,其中有兩個私有屬性id和name;擁有一個構造方法和一個私有方法print;
- 還有一個public內部類BaseInfo:含有兩個私有屬性nation和bloodType;擁有一個構造方法和一個私有方法print;
- 還有一個private內部類FamilyInfo:含有兩個私有屬性nativePlace和address,擁有一個構造方法和一個私有方法print。

由於FamilyInfo爲私有的,因此爲了可以初始化其屬性,在Person中添加了一個私有屬性,並在構造方法中對其進行了初始化。

public class Person {
    private String id;
    private String name;

    private FamilyInfo familyInfo;

    public Person(String id, String name) {
        this.id = id;
        this.name = name;
        this.familyInfo = this.new FamilyInfo("beijing", "beijing");
    }

    private void print() {
        System.out.println("Person{id=" + id + ", name=" + name + "}");
    }

    public class BaseInfo {
        private String nation;
        private String bloodType;

        public BaseInfo(String nation, String bloodType) {
            this.nation = nation;
            this.bloodType = bloodType;
        }

        private void print() {
            System.out.println("BaseInfo{nation=" + nation + ", bloodType=" + bloodType + "}");
        }
    }

    private class FamilyInfo {
        private String nativePlace; // 籍貫
        private String address;     // 住址

        private FamilyInfo(String nativePlace, String address) {
            this.nativePlace = nativePlace;
            this.address = address;
        }
        private void print() {
            System.out.println("FamilyInfo{nativePlace=" + nativePlace + ", address=" + address + "}");
        }
    }
}

下面的Main方法中,初始化了Person類,通過一個getFiledFromPerson()方法打印出其私有屬性、私有方法、內部類私有屬性及方法。

public class Main {

    private static void getFiledFromPerson(Person person, Person.BaseInfo baseInfo) {
        try {
            // 獲取外部類的私有屬性
            Field idField = person.getClass().getDeclaredField("id");
            idField.setAccessible(true);
            String id = (String) idField.get(person);
            System.out.println("id:" + id);

            Field familyInfoField = person.getClass().getDeclaredField("familyInfo");
            familyInfoField.setAccessible(true);
            Object familyInfo = familyInfoField.get(person);

            // 獲取外部類的私有方法
            Method printPersonMethod = person.getClass().getDeclaredMethod("print");
            printPersonMethod.setAccessible(true);
            printPersonMethod.invoke(person);

            // 獲取內部類的私有屬性
            Class baseInfoClz = Class.forName("demo.Person$BaseInfo");
            Field nationField = baseInfoClz.getDeclaredField("nation");
            nationField.setAccessible(true);
            String nation = (String) nationField.get(baseInfo);
            System.out.println("nation:" + nation);

            Class familyInfoClz = Class.forName("demo.Person$FamilyInfo");
            Field field = familyInfoClz.getDeclaredField("address");
            field.setAccessible(true);
            String address = (String) field.get(familyInfo);
            System.out.println("address:" + address);

            // 獲取內部類的私有方法
            Method printBaseInfoMethod = baseInfoClz.getDeclaredMethod("print");
            printBaseInfoMethod.setAccessible(true);
            printBaseInfoMethod.invoke(baseInfo);

            Method printFamilyInfoMethod = familyInfoClz.getDeclaredMethod("print");
            printFamilyInfoMethod.setAccessible(true);
            printFamilyInfoMethod.invoke(familyInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Person person = new Person("1001", "John"); // 初始化Person以及默認FamilyInfo
        Person.BaseInfo baseInfo = person.new BaseInfo("han", "A"); // 初始化BaseInfo
        getFiledFromPerson(person, baseInfo);
    }
}
發佈了54 篇原創文章 · 獲贊 15 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章