java反射之Method的invoke方法實現

Class (反射的入口)Method (成員方法)Field (成員變量)java

java反射經常使用的一些實例ide

package cn.com;

import java.lang.reflect.Method;

/**
 * Copyright (C), 2018-2019
 *
 * @Description: TODO
 * @Author: zhou
 * @Create: 2019/10/10 16:36
 * @Version 1.0.0
 */

public class MethodInvoke {
    public static void main(String[] args) throws Exception {

        Class implClass = Class.forName("cn.com.Animal");
        Object instance = implClass.newInstance(); // 實例
        System.out.println("instance:" + instance);
        Method method = instance.getClass().getMethod("print");
        method.invoke(instance);

        Method method1 = implClass.getDeclaredMethod("print");
        method1.invoke(instance);

     // 訪問是有方法 printS
     Method privteMethod = implClass.getDeclaredMethod("printS");
     privteMethod.setAccessible(true); //設置或取消訪問檢查,以達到訪問私有對象的目的。
     privteMethod.invoke(instance);

        Method animalMethod = Animal.class.getDeclaredMethod("print");
        Method catMethod = Cat.class.getDeclaredMethod("print");

        Animal animal = new Animal();
        Cat cat = new Cat();
        animalMethod.invoke(cat);
        animalMethod.invoke(animal);
        System.out.println("=====");
        catMethod.invoke(cat);
        catMethod.invoke(animal);
    }
}

class Animal {

    public void print() {
        System.out.println("Animal.print()");
    }
  private void printS(){
  System.out.println("Animal.privateFunction");
  }
} 

class Cat extends Animal { @Override public void print() { System.out.println("Cat.print()"); } }

 

獲取反射的方法有:ui

第一種:
Class animal =Animal.class;
第二種:
Class animal = Class.forName("cn.com.Animal"); // Animal類的全路徑
獲取到 Class 以後,即可以獲取有參方法
Method method = animal.getDeclaredMethod(String name, Class<?>... parameterTypes);
Method method = animal.getMethod(String name, Class<?>... parameterTypes); 
其中: name 爲方法名,paramterTypers方法的參數類型

能夠經過 Object instance = animal.
newInstance(); 將類實例化

最後經過
method.invoke(instance, parameValue);
instance爲類是實例化,paramValue爲方法參數(根據實際狀況傳入)

java反射可饒過不能訪問私有方法的限制,須要添加
setAccessible(true);  //設置或取消訪問檢查,以達到訪問私有對象的目的。

 接下來,咱們來看看invoke()方法的實現過程。
@CallerSensitive
    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
              
                Class<?> caller = getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

invoke()方法中主要分爲兩部分:訪問控制檢查和調用MethodAccessor.invoke()實現方法執行。this

訪問控制檢測分有3步:spa

一、檢查override.net

二、快速檢查,判斷該方法的修飾符modifiers是否爲public3d

三、詳細檢查,經過方法的(protected/private/package)修飾符或方法的聲明類(例如子類能夠訪問父類的protected方法)與調用者caller之間的關係,判斷caller是否有權限訪問該方法。code

override屬性是Method的父類AccessibleObject中聲明的變量,使得程序能夠控制是否跳過訪問權限的檢查。另外,Method的實例對象中,override屬性的初始值設置爲false。
  public void setAccessible(boolean flag) throws SecurityException {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
        setAccessible0(this, flag);
    }

    /* Check that you aren't exposing java.lang.Class.<init>. */
    private static void setAccessible0(AccessibleObject obj, boolean flag)
        throws SecurityException
    {
        if (obj instanceof Constructor && flag == true) {
            Constructor<?> c = (Constructor<?>)obj;
            if (c.getDeclaringClass() == Class.class) {
                throw new SecurityException("Can not make a java.lang.Class" +
                                            " constructor accessible");
            }
        }
        obj.override = flag;
    }
 

 

部分代碼來源:https://blog.csdn.net/wenyuan65/article/details/81145900
相關文章
相關標籤/搜索