The invoke Method of Java reflection Method is implemented, and Ali Java development interview answers

Posted by MastahUK on Sat, 25 Dec 2021 07:55:07 +0100

Next, let's take a look at the implementation of the invoke() method.

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{

        if (!override) {

            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {

                Class<?> caller = Reflection.getCallerClass(1);

 

                checkAccess(caller, clazz, obj, modifiers);

            }

        }

        MethodAccessor ma = methodAccessor;             // read volatile

    if (ma == null) {

        ma = acquireMethodAccessor();

    }

    return ma.invoke(obj, args);

}

The invoke () method is mainly divided into two parts: access control checking and calling methodaccessor invoke() implements method execution.

First, let's look at the logic of access control check. When you first see the logic here, it's easy to wonder what it is. Generally speaking, it is to judge whether the caller of a method can access the method through the modifier of the method (public/protected/private/package). This is the basic content of java, but it's not easy to think of it in code. The access control check is divided into three steps:

  1. Check override. If override is true, skip the check; Otherwise, continue;

  2. Check quickly to determine whether the modifier modifiers of the method is public. If so, skip the check; Otherwise, continue;

  3. Check the relationship between the (protected/private/package) modifier of the method or the declared class of the method (for example, the subclass can access the protected method of the parent class) and the caller caller to determine whether the caller has permission to access the method.

The override attribute is a variable declared in the AccessibleObject of the parent class of Method, which enables the program to control whether to skip the access permission check. In addition, in the instance object of Method, the initial value of override property is set to false.

public void setAccessible(boolean flag) throws SecurityException {

        SecurityManager sm = System.getSecurityManager();

        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);

        setAccessible0(this, flag);

    }

 

    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;

}

To add another word, Field also inherits AccessibleObject, and Field override is initialized to false, that is, different values are not initialized according to variable modifiers. But we're calling Field When setting (object obj, object value), if the Field is decorated with private, an exception will be thrown due to lack of access permission. Therefore, setAccessible(true) must be called. It is easy to understand here that because the variable is public, override is initialized to true.

In the invoke() method, after the access control check, it is through the methodaccessor invoke() calls the method. Let's look at the code:

MethodAccessor ma = methodAccessor;             // read volatile

if (ma == null) {

    ma = acquireMethodAccessor();

}

return ma.invoke(obj, args);

The logic here is very simple. First, assign the variable methodAccessor to ma, and save a local variable that can be directly referenced in the method stack. If the methodAccessor does not exist, call the acquireMethodAccessor() method to create one.

 private volatile MethodAccessor methodAccessor;

    private Method root;

    

    private MethodAccessor acquireMethodAccessor() {

        // First check to see if one has been created yet, and take it

        // if so

        MethodAccessor tmp = null;

        if (root != null) tmp = root.getMethodAccessor();

        if (tmp != null) {

            methodAccessor = tmp;

        } else {

            // Otherwise fabricate one and propagate it up to the root

            tmp = reflectionFactory.newMethodAccessor(this);

            setMethodAccessor(tmp);

        }

 

        return tmp;

    }

 

    void setMethodAccessor(MethodAccessor accessor) {

        methodAccessor = accessor;

        // Propagate up

        if (root != null) {

            root.setMethodAccessor(accessor);

        }

    }

 

    Method copy() {

        Method res = new Method(clazz, name, parameterTypes, returnType,

                                exceptionTypes, modifiers, slot, signature,

                                annotations, parameterAnnotations, annotationDefault);

        res.root = this;

        res.methodAccessor = methodAccessor;

        return res;

    }

Combining acquireMethodAccessor(),setMethodAccessor() and copy(), we can see that a method instance object maintains a root reference. When calling method When copying the method with copy (), root points to the copied object. Then, when a Method is copied many times, once the setMethodAccessor () method is invoked, it will also assign the root reference to the methodAccessor variable of the Method pointed to. For example: D - > C - > b - > A, where X - > y means X = Y.copy(). When C object calls setMethodAccessor(), both B and a will propagate the assignment methodaccessor, while D's methodaccessor is still null. Next, when D calls acquireMethodAccessor() to obtain a methodaccessor, D obtains the root methodaccessor, and D will hold the same methodaccessor as ABC.

Although in Method, maintaining the root reference is intended to keep the same Method with only one methodAccessor instance, the above methods still cannot guarantee that the same Method has only one methodAccessor instance. For example, use copy() to maintain the relationship between ABCD: D - > C - > b - > A. when the B object calls setMethodAccessor(), both B and a will assign a methodAccessor, while the methodaccessors of C and D are still null. At this time, when D calls acquireMethodAccessor(), D obtains root, that is, C's methodAccessor. It is found to be empty, and then a new one is created. Thus, there are two methodAccessor instance objects in the same Method.

In class getMethod(),Class. Getdeclaraedmethod() and class The getdeclaredmethod (string name, class <? >... parameterTypes) Method will eventually call the copy() Method to ensure the security of the Method. In the case of extreme coincidence, it may cause the problem of class expansion. This is the implementation mechanism of MethodAccessor to be discussed next.

In the previous code, the MethodAccessor is created through the newMethodAccessor(Method) method of the ReflectionFactory.


## last

**It's not easy to code. If you think it's helpful, you can praise it and let more people in need see it**

It's another job season. Here, I've prepared a set for you Java Programmers select high-frequency written interview questions to help you overcome them BAT of offer,Topics range from elementary Java A series of interview questions and answers from basic to advanced distributed architecture are used for your reference,**What you need is OK[You can get it here for free](https://gitee.com/vip204888/java-p7) * *, the following is a screenshot of some contents
 To create.



last

It's not easy to code. If you think it's helpful, you can praise it and let more people in need see it

It's another job season. Here, I've prepared a set of high-frequency written interview questions selected by Java programmers to help you win BAT's offer. The topics range from primary Java foundation to advanced distributed architecture. A series of interview questions and answers can be used as a reference for you You can get it here for free , here are some screenshots

Topics: Java Back-end Interview Programmer