Java反射知識小結

反射知識在我近期的開發中用到的不過,所以知識點也不是很清楚。今天補習了一下反射部分內容,在這里做一個小結。

  1. Java反射的概念
      反射含義:可以獲取正在運行的Java對象。

  2. Java反射的功能
      1)可以判斷運行時對象所屬的類
      2)可以判斷運行時對象所具有的成員變量和方法
      3)通過反射甚至可以調用到private的方法
      4)生成動態代理

  3. Java反射機制

    • 在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;
      對于任意一個對象,都能夠調用它的任意一個方法;
      這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
    • Java反射機制主要提供了以下功能:
      在運行時判斷任意一個對象所屬的類;
      在運行時構造任意一個類的對象;
      在運行時判斷任意一個類所具有的成員變量和方法;
      在運行時調用任意一個對象的方法;
      生成動態代理。
  4. 實現Java反射的類
      1) Class:它表示正在運行的Java應用程序中的類和接口
      2) Field:提供有關類或接口的屬性信息,以及對它的動態訪問權限
      3) Constructor:提供關于類的單個構造方法的信息以及對它的訪問權限
      4) Method:提供關于類或接口中某個方法信息
      注意:Class類是Java反射中最重要的一個功能類,所有獲取對象的信息(包括:方法/ 屬性/構造方法/訪問權限)都需要它來實現。

  5. 編寫Java反射程序的步驟:
      1) 必須首先獲取一個類的Class對象
      例如(推薦第一種):
      Class c1 = Test.class;
      Class c2 = Class.forName(“com.reflection.Test”);
      Class c3 = new Test().getClass();
      2) 然后分別調用Class對象中的方法來獲取一個類的屬性/方法/構造方法的結構
      注意:如果要能夠正常的獲取類中方法/屬性/構造方法應該重點掌握如下的反射類
      Field
      Constructor
      Method


常用方法

//首先要獲取一個類的Class對象
Class c1 = TestReflection.class;
或:Class<Bean> c1 = (Class<Bean>) Class.forName(className);
或:Class<Bean> c1 = (Class<Bean>) new Bean().getClass();

//生成一個實例 
Bean b = (Bean)c1.newInstance(); 

//獲取指定的包名
String package01 = c1.getPackage().getName();
//獲取類的修飾符
int mod = c1.getModifiers();
//獲取指定類的完全限定名
String className = c1.getName();
//獲取指定類的父類
Class superClazz = c1.getSuperclass();
//獲取實現的接口
Class[] interfaces = c1.getInterfaces();


//獲取指定類的所有成員變量:(類或接口所聲明的所有字段,public, private, protected ,但不包括從基類繼承的字段)
Field[] fields = c1.getDeclaredFields();

for (Field field : fields) {    
    //獲取每個字段的訪問修飾符
  modifier = Modifier.toString(field.getModifiers()); 
    //獲取字段的數據類型所對應的Class對象
  Class type = field.getType(); 
    //獲取字段名
  String name = field.getName(); 

    //如果是數組類型則需要特別處理
  if (type.isArray()) { 
    String arrType = type.getComponentType().getName() +"[]";
    System.out.println("" + modifier + " " + arrType + " "+ name + ";");
  } else {
    System.out.println("" + modifier + " " + type + " " + name + ";");
  }
}

//獲取指定類的指定成員變量(前者為全部,后者僅為公有,但包含基類)
Field field = c1.getDeclaredField("mScroller");
Field field = c1.getField("mScroller");

實例(獲取指定類的指定成員變量):
初始化ViewPager時,利用獲得指定成員變量,來反射修改滑動速度。

public class ViewPagerScroller extends Scroller {
    
    // 設置滑動速度
    private int mScrollDuration = 2000;             
 
    public void setScrollDuration(int duration){
        this.mScrollDuration = duration;
    }
     
    public ViewPagerScroller(Context context) {
        super(context);
    }
 
    public ViewPagerScroller(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }
 
    public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) {
        super(context, interpolator, flywheel);
    }
 
    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        super.startScroll(startX, startY, dx, dy, mScrollDuration);
    }
 
    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        super.startScroll(startX, startY, dx, dy, mScrollDuration);
    }
      
    public void initViewPagerScroll(ViewPager viewPager) {
        try {
            //在這里使用了反射,獲得ViewPager類的指定成員變量
            Field mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            //將ViewPager的實例,即傳入作為形參的viewPager對象,也就是主界面程序中的mViewPager對象,中的成員變量mScroller設置為this
            mScroller.set(viewPager, this);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

    //在主界面程序中使用ViewPager的時候,這樣初始化:
     mViewPager = (ShowViewPager) getActivity().findViewById(R.id.viewpager);
     ViewPagerScroller viewPagerScroller = new ViewPagerScroller(getActivity());
     viewPagerScroller.initViewPagerScroll(mViewPager);

獲取指定類的所有方法的兩種方式:
public Method[] getMethods():返回某個類的所有public方法,包括從基類繼承的、從接口實現的所有public方法。
public Method[] getDeclaredMethods():返回某個類自身聲明的所有方法(public, private, protected),包括從所實現接口的方法,但不包括繼承的方法。


getMethod獲取指定方法的用法舉例:

  • 執行某對象的方法
public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {  
   
     //首先得到這個對象的Class
     Class ownerClass = owner.getClass();  
   
     //配置參數的Class數組,作為尋找Method的條件
     Class[] argsClass = new Class[args.length];
     for (int i = 0, j = args.length; i < j; i++) {  
         argsClass[i] = args[i].getClass();  
     }  
  
     //得到要執行的Method
     Method method = ownerClass.getMethod(methodName,argsClass);  
   
     //執行該Method.invoke方法的參數是執行這個方法的對象owner,和參數數組args。可以這么理解:owner對象中帶有參數args的method方法。返回值是Object,也既是該方法的返回值。
     return method.invoke(owner, args);  
}  
  • 執行某個類的靜態方法
public Object invokeStaticMethod(String className, String methodName,  
             Object[] args) throws Exception {  
    Class ownerClass = Class.forName(className);  
   
    Class[] argsClass = new Class[args.length];  
    for (int i = 0, j = args.length; i < j; i++) {  
         argsClass[i] = args[i].getClass();  
    }  
   
    Method method = ownerClass.getMethod(methodName,argsClass);  
   
    //invoke的一個參數是null,因為這是靜態方法,不需要借助實例運行
    return method.invoke(null, args);  
 }

解釋一下getMethod(String name, Class<?>... parameterTypes)方法中的兩個參數:

  • 第一個參數是方法名,第二個參數是該方法的參數類型數組
  • 因為存在同方法名不同參數這種情況,所以只有同時指定方法名和參數類型才能唯一確定一個方法。
    如一個函數: int test(int a, String str);
    對應的getMethod方法:
    getMethod("test",int.class, String.class);
    或:getMethod("test",new Class[]{ int.class, String.class } );

method.invoke(Object receiver, Object... args)
就是最后一步:執行改類的指定方法了。
需要注意的是其第二個參數,不同于getMethod的第二個參數。

  • 前者是該方法參數的實際的值。
  • 后者是該方法參數的實際的值的參數類型。

invoke方法的返回值即為該方法實際的返回值類型,包裝成Object,可以向下強轉。


已上面的例子為例引出一個疑問:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一:java概述:1,JDK:Java Development Kit,java的開發和運行環境,java的開發工...
    ZaneInTheSun閱讀 2,687評論 0 11
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,908評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,764評論 18 399
  • 我這一生,許多不幸,許多心酸。曾經背負著克星,煞星,我也不曾低頭過。我的出生,沒有喜悅與祝福,而是斥責與謾罵,...
    青冥杳兮閱讀 253評論 0 0
  • 人生為了什么,才有這樣凄涼的夜。 ——蕭紅 人生是漫長的,特別是對于窮人來說,他們不僅僅要...
    一紀重華閱讀 581評論 0 4