1. 程式人生 > >反射的原理及應用

反射的原理及應用

原理:反射首先是能夠獲取到Java中的反射類的位元組碼,然後將位元組碼中的方法,變數,建構函式等對映成 相應的 Method、Filed、Constructor 等類
應用:取出類的modifiers,資料成員,方法,構造器,和超類
找出某個接口裡定義的常量和方法說明.
取得和設定物件資料成員的值,如果資料成員名是執行時刻確定的也能做到.
在執行時刻呼叫動態物件的方法.

1,類的載入

當程式要使用某個類時,如果該類還未被載入到記憶體中,則系統會通過載入,連線,初始化三步來實
現對這個類進行初始化。

  • 載入 就是指將 class 檔案讀入記憶體,併為之建立一個 Class 物件。 任何類被使用時系統都會建立一個 Class 物件
  • 連線 驗證 是否有正確的內部結構,並和其他類協調一致 準備 負責為類的靜態成員分配記憶體,並設定預設初始化值 解析 將類的二進位制資料中的符號引用替換為直接引用
  • 初始化

1.2類的初始化

  1. 建立類的例項
  2. 類的靜態變數,或者為靜態變數賦值
  3. 類的靜態方法
  4. 使用反射方式來強制建立某個類或介面對應的 java.lang.Class 物件
  5. 初始化某個類的子類

1.3反射概述

Java 反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱 為 java 語言的反射機制。

要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖這個類,使用的就是 Class 類中的方法,所以先要獲取到每一個位元組碼檔案所對應的 Class 型別物件。

1.4準備資料,我就用我現在的寫的專案的資料,大家隨意

在這裡插入圖片描述

1.5 知識儲備

需要掌握 6 個單詞

  • Class 類
  • Constructor 構造
  • Method 方法
  • Filed 欄位
  • instance 例項
  • invoke 執行

1.6 Class 獲得方式

在這裡插入圖片描述

public class A {
    /**
     * class獲得方式
     *
     * @param args
     */
public static void main(String[] args) { //1 通過型別獲得 // 語法:類名.class // 應用場景:確定型別 等 Class clazz1 = BrandController.class; System.out.println("語法:類名.class|" + clazz1); //2 通過例項物件獲得 // 語法:變數.getClass() // 應用場景:在方法內部通過引數獲得型別 等 BrandController brandController = new BrandController(); Class<? extends BrandController> aClass = brandController.getClass(); System.out.println("語法:變數.getClass()|" + aClass); //3 通過字串獲得 // 語法:Class.forName("全限定類名") // 應用場景:通過配置獲得字串 等 try { Class<?> aClass1 = Class.forName("com.controller.BrandController"); System.out.println("Class.forName(\"全限定類名\")|"+aClass1); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }

1.6.1 得到這個類的名字

在這裡插入圖片描述

      //1 獲得 Class
       Class clazz = User.class;
       // 得到這個類的名字:全限定類名
        String name = clazz.getName();
        //  這個只是類的名字
        String simpleName = clazz.getSimpleName();
        System.out.println(" 這個只是類的名字simpleName:"+simpleName);

        System.out.println("得到這個類的名字:全限定類名name:"+name);




1.7構造方法與例項

在這裡插入圖片描述

public class A {
    /**
     * 構造方法與例項
     *
     * @param args
     */
    public static void main(String[] args) {
        //無參構造 , 並例項化

        //1 獲得 Class
        Class<SpecificationOption> specificationOptionClass = SpecificationOption.class;
        System.out.println("獲得 Class"+specificationOptionClass);
        //2 獲得構造 -- 沒有形參
        Constructor<SpecificationOption> constructor = null;
        try {
            constructor = specificationOptionClass.getConstructor();
            System.out.println("獲得構造 -- 沒有形參"+constructor);
            SpecificationOption specificationOption = constructor.newInstance();
            System.out.println("例項物件,沒有實參"+specificationOption);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

獲取無參的簡化版

在這裡插入圖片描述


public class A {
    /**
     * 構造方法與例項
     *
     * @param args
     */
    public static void main(String[] args) {
        //無參構造 , 並例項化

        //1 獲得 Class
        try {
            // 獲得無參的簡化版
            SpecificationOption specificationOption = SpecificationOption.class.newInstance();
            System.out.println(specificationOption);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }
}

獲取有參構造

在這裡插入圖片描述
在這裡插入圖片描述

public static void main(String[] args) {
        //有參構造 , 並例項化
        //1 獲得 Class
        Class beanClass = SpecificationOption.class;
        //2 獲得構造 -- 三個字串形參 -- (Integer.class,String.class,Integer.class)
        Constructor constructor = null;
        try {
            constructor = beanClass.getConstructor(Integer.class, String.class, Integer.class);
            System.out.println("獲得構造 -- 三個字串形參" + constructor);
            //3 例項物件,三個字串實參
            Object o = constructor.newInstance(2323,"白色", 1);
            System.out.println(o);
        } catch (Exception e) {
            e.printStackTrace();

        }

    }

1.7.5 擴充套件:私有構造(暴力反射)

  • 修改 Bean 新增私有構造
private Bean(String id) {
this.id = id;
System.out.println("有參構造:" + id);
}
  • getConstructor() 使用該方法將無法獲得私有方法,程式執行拋異常
  • 在這裡插入圖片描述
  • 沒有使用 setAccessible(true),將拋異常
  • 在這裡插入圖片描述
    在這裡插入圖片描述
@Test
public void testPrivateCons() throws Exception{
//私有構造
//1 獲得 Class
Class beanClass = Bean.class;
//2 獲得構造 -- 兩個字串形參 -- Bean(String id, String className)
// * getConstructor() 將拋異常 java.lang.NoSuchMethodException
// * getDeclaredConstructor 可以獲得私有構造
Constructor constructor = beanClass.getDeclaredConstructor(String.class)
//暴力訪問
constructor.setAccessible(true);
//3 例項物件,兩個字串實參
Object bean = constructor.newInstance("userId");
System.out.println(bean);

1.8方法與執行

1.8.1public 方法
  • 獲得方法並設定
    在這裡插入圖片描述
  //1 獲得 Class
        Class clazz = User.class;
        //2 獲得例項 ,相當於 Object obj = new Bean();
        Object obj = clazz.newInstance();
        //3 操作 setAge 方法
        // * 格式:getMethod(方法名,形成列表)
        Method setMethod = clazz.getMethod("setAge", Integer.class);

        System.out.println("getMethod(方法名,形成列表)"+setMethod);
        //3.2 執行方法,一個實參
        Object setReturnObj = setMethod.invoke(obj, 12);
        System.out.println("set 方法返回值:" + setReturnObj);

1.8.2私有方法(暴力反射)private

新增私有方法
在這裡插入圖片描述

在這裡插入圖片描述


        //4 操作 getId 方法
        // 4.1 獲得方法,沒有形參
        Method getMethod = clazz.getMethod("getAge");
        // 4.2 執行方法,沒有實參
        Object getReturnObj = getMethod.invoke(obj);
        System.out.println("get 方法返回值:" + getReturnObj);


         //5 暴力反射私有的構造方法
        Method showMethod = clazz.getDeclaredMethod("show");
        System.out.println("暴力反射私有的構造方法show     "+showMethod);
         //暴力訪問
        showMethod.setAccessible(true);
          // 4 執行方法,沒有實參
        // obj.setMethod(args)     user.setAge(20)
        Object invoke = setMethod.invoke(obj, 20);
        Object result = showMethod.invoke(obj);
        System.out.println("show私有"+result);

1.8.3 main 方法與執行

新增main方法
在這裡插入圖片描述

在這裡插入圖片描述

 //有參構造 , 並例項化
        Class<User> clazz = User.class;
        //2 獲得方法 -- main 靜態方法 -- public static void main(String[] args)
        Method mainMethod = clazz.getMethod("main", String[].class);
        Object getReturnObj =  mainMethod.invoke(null, (Object)new String[]{"aaa","bbb"});
        System.out.println("main 方法返回值:|||||||||" + getReturnObj);

1.8.4 public 欄位的操作

在這裡插入圖片描述


  //5 操作欄位,進行賦值,public String  name;
        //5.1 獲得的欄位,一個形參
        // * 格式:getField(欄位名)
        Field descriptionField = clazz.getField("name");
        System.out.println("getField(欄位名)     "+descriptionField);

        //5.2 為物件的欄位賦值
        descriptionField.set(obj, "喜歡在文字中傾訴");

        //5.3 獲取物件的欄位值
        Object fieldReturnObj = descriptionField.get(obj);
        System.out.println("description 欄位返回值:       "+fieldReturnObj);


1.8.5 private 欄位的操作

在這裡插入圖片描述

在這裡插入圖片描述

   //5 操作欄位,進行賦值,private String  name;
        //5.1 獲得的欄位,一個形參
        // * 格式:getDeclaredField(欄位名)
        Field descriptionField = clazz.getDeclaredField("name");
        System.out.println("getDeclaredField(欄位名)     "+descriptionField);
        //暴力訪問
        descriptionField.setAccessible(true);
        //5.2 為物件的欄位賦值
        descriptionField.set(obj, "喜歡在文字中傾訴");

        //5.3 獲取物件的欄位值
        Object fieldReturnObj = descriptionField.get(obj);
        System.out.println("description 欄位返回值:       "+fieldReturnObj);