JAVA類反射之類的調用

類的調用(調用類中的成員)
★ 構造類對象
使用構造器新建對象。根據指定的參數類型找到相應的構造函數,傳入相應參數調用執行,以創建一個新的對象實例。
★ 調用方法
根據方法名稱執行方法。根據方法名與參數類型匹配指定的方法,傳入相應參數與對象進行調用執行。若是靜態方法,則不需傳入具體對象。
★ 獲取與設置屬性值
根據屬性名稱讀取與修改屬性的值,訪問非靜態屬性需傳入對象爲參數。

代碼示例:

package cn.hncu.reflect;

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

import org.junit.Test;
/*
    一道面試題:創建(獲得)一個類對象有幾種方式?
    new,  克隆   ,  反序列化,  類反射
*/
public class ReflectOperateObj {
   //private static final String className="cn.hncu.reflect.Student"; 
   private static final String className="cn.hncu.reflect.Person"; 

   @Test//使用構造器新建對象,最核心的代碼: Constructor con= c.getConstructor(paramTypes);  con.newInstance(args);
   public void operateConstructor(){
       try {
        //Person p = new Person(); //寫死了
           Class c = Class.forName(className);

           //1空參構造方法
           //簡便方式new一個空參對象
           Object obj = c.newInstance();//選用空參構造方法新建一個對象
           System.out.println(obj);
          //常規方式:先拿到對應構造器的對象,然後利用該構造器對象(代表那個構造函數)調用newInstance()方法造出對象
           Constructor con = c.getConstructor(null);//獲取空參構造方法
          Object obj2 = con.newInstance(null);
          System.out.println(obj2); 

          //2 非空參構造方法
          //只能常規方法:必須先通過形參獲得對應的構造方法,然後通過實參調用該構造方法
          //public Person(String name, int age)
         //Person p = new Person("Jack",22);
          //2.1獲取指定的構造器--通過形參
          Class parameterTypes[] = new Class[2];
          parameterTypes[0] = String.class;
          parameterTypes[1] = Integer.TYPE;
         Constructor con2= c.getConstructor(parameterTypes);
          //2.2調用該構造器來new對象---通過實參
         Object params[] = new Object[2];//調用構造方法是要傳入的參數
         params[0]=new String("Jack");
         params[1]=new Integer(24);
         Object obj3 = con2.newInstance(params);
          System.out.println(obj3);

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

   @Test//調用普通方法---最核心的代碼: Method m = c.getMethod(name,paramTypes);  m.invoke(obj,args);
   public void callMethod(){
       try {
           Class c = Class.forName(className);

           //1調用空參方法---Person p = new Person(); p.toString();
           //1.1先獲得該Method對象---通過形參
           Method m = c.getMethod("toString", null);
           //1.2再讓該Method對象執行---通過實參
           Object p = c.newInstance();
           Object returnValue = m.invoke(p, null);//執行方法---p.toString()
           System.out.println(">>>> "+ returnValue);

           System.out.println("----------------");

           //2調用非空參方法
           //2.1先獲得該Method對象---通過形參
           Class parameterTypes[] = new Class[2];
           parameterTypes[0] = int.class;//參數類型爲int--OK
           //parameterTypes[0] = Integer.TYPE;//參數類型爲int--OK
           //下句小細節:因爲這是一個純粹的類,裏面沒有拆箱功能,無法當作int類型。但如果sum()中的第一個參數就是Integer類型,那麼下句OK
           //parameterTypes[0] = Integer.class;//參數類型爲int--ERROR

           parameterTypes[1] = int.class;
           Method m2 = c.getDeclaredMethod("sum", parameterTypes);

           //2.2再讓該Method對象執行---通過實參  p.sum(100,200);
           Object p2 = c.newInstance();
           Object args[] = new Object[2];
           args[0] = 1;
           args[1] =100;
           Object res = m2.invoke(p2, args);
           System.out.println("res: " + res);

           //3 調用靜態方法
           Method m3 = c.getMethod("aa", null);
           m3.invoke(null, null);//靜態方法的調用不需要對象,類名可以省略,所以傳入null就行。至於方法的實參,同前

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

   @Test//訪問屬性(成員變量、類變量)----最核心代碼:  Field fld = c.getFild(name); 專用setter-getter方法:fld.setDouble(p,value);fld.getDouble(p)  通用setter-getter方法:fld.set(p,value);fld.get(p)
   //Person p = new Person(); p.value=11.22;
   public void AccessField(){
       try {
           Class c = Class.forName(className);
           //獲取Field對象
           Field fld = c.getField("value");
           //操縱該Field對象,以進行讀寫屬性值
           Object p = c.newInstance();
           //通用的setter-getter方法
           //fld.set(p,11.22);//設置值
           //double x = (Double)fld.get(p) + 100;//獲取值
           //專用的setter-getter方法
           fld.setDouble(p, 22.33);
           double x = fld.getDouble(p) + 100;//獲取值
           System.out.println(x);
       } catch (Exception e) {
           e.printStackTrace();
       }
   }


    //暴力訪問---訪問類中的私有成員(構造器、普通方法、屬性)---這三者的公共父類AccessibleObject中的方法setAccessible(boolean flag)可以打開私有訪問權限
   @Test//強行訪問私有方法: private int sum(int n)
   public void AccessBlood(){
       try {
           Class c = Class.forName(className);
           Method m = c.getDeclaredMethod("sum", int.class);
           m.setAccessible(true);//暴力訪問,打開訪問權限。---其實是調用父類AccessibleObject中的該方法
           Object res = m.invoke(c.newInstance(), 100);
           System.out.println(res);

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


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