Java annotations sort of knowledge - (notes used when running) reflection

Java annotations sort of knowledge - (notes used when running) reflection

Earlier we combed the knowledge and the use of annotations annotation processor, and now we sort of comment about the run-time use.

A run-time annotation, annotation information will be loaded into the JVM, this time we can not re-write the code that processes treated according to the specific circumstances of the operation, we can only comment about the elements to get information based on logic code may run, and then do some processing, which requires use of java reflection,

What is and what is the use of reflection

Reflex (Reflection) is a characteristic of Java, Java can get information through any object of reflection, after obtaining the information of the object can do some purposes:

  • Analyzing the class object belongs
  • Examples of the object
  • The object is to obtain all the following member variables and methods
  • Call variables and methods in the object

In short, by reflection, we can get compiled each class and the information, and then instantiate the object, call the method.

We in the development process, IDE automatically prompts framework such as Spring and large, are using the principle of reflection. Android utilizing reflection is relatively well-known frame EventBus frame. We will write a simple simulation of EventBus to understand the specific role of reflection.

EventBus to do with the message distribution, our role is to comment after listening method of an object in a class, when a message is sent to the object, the place of registration can receive the message. EventBus used as follows:

  1. A change in the definition of the object to be notified:

    public static class MessageEvent { /* Additional fields if needed */ }
    
  2. Define a comment, and indicated that it is the thread which informs whether the main thread

    @Subscribe(threadMode = ThreadMode.MAIN)  
    public void onMessageEvent(MessageEvent event) {/* Do something */};
    

    Register, unregister need to accept the message class changes

     @Override
     public void onStart() {
         super.onStart();
         EventBus.getDefault().register(this);
     }
    
     @Override
     public void onStop() {
         super.onStop();
         EventBus.getDefault().unregister(this);
     }
    
  3. Send a message

     EventBus.getDefault().post(new MessageEvent());
    

Follow step by step my left hand to write code

Since the code names are free, and here EventBus consistent.

Creating ThreadMode enumeration

@Subscribe (threadMode = ThreadMode.MAIN) The sentence can be analyzed, we need to give the annotation an enumerated type, a method to distinguish between markers are used in the main thread or a child thread:

public enum ThreadMode {
    MAIN,//主线程
    OTHER//子线程
}

Creating notes Subscribe

This comment has the following features:

  • Notes runtime
  • There is a property called threadMode, enumeration parameters ThreadMode
  • The notes marked on the method
@Target(ElementType.METHOD)//标注的类型在方法上
@Retention(RetentionPolicy.RUNTIME)//运行时注解
public @interface Subscribe {
    //一个线程属性,默认是在主线程运行
    ThreadMode threadMode() default ThreadMode.Main;
}

Create a need to notify the object MessageEvent

/**
 * 通知的对象
 * AnnotationApplication
 * Created by anonyper on 2019/6/6.
 */
public class MessageEvent {
    /**
     * 一个消息变量
     */
    String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

   

    public MessageEvent(String message) {
        this.message = message;
    }
}

Create a class EventBus relevant code

EventBus class functions mainly in the following two points:

Management object registration

According to a message bean to be notified to get concerned about the message bean object, and then call the method of the object under notice

According to functional analysis:

1, EventBus global common, need to be a single-mode embodiment, only there is only a target item.

2, when sending the notification message to identify the message receiving method change, and then executed.

3, at the same time there will be multiple objects may need to listen to the same message of change (MainActivity and SetActivity listens SMS messages)

4, a plurality of object might need to change listener messages (an Activity monitor network message, SMS message)

5, so the time of registration, you need to find all marked @Subscribe annotated method in the object

6, so finding marked @Subscribe annotation methods need to save up, there is a need to change the information carrying Bean object methods.

7, execution of the method is performed by reflection, method.invoke (Object obj, Object ... obj2), a first object of the method belongs, is the second parameter method.

8, the method carries information Bean we define MethodBean, including the following:

/**
 * 方法bean
 * AnnotationApplication
 * Created by anonyper on 2019/6/6.
 */
public class MethodBean {
    /**
     * 该方法对应的类对象
     */
    Object object;
    /**
     * 方法对象
     */
    Method method;
    /**
     * 运行线程指定
     */
    ThreadMode threadMode;
    /**
     * 参数类型
     */
    Class<?> eventType;

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public void setThreadMode(ThreadMode threadMode) {
        this.threadMode = threadMode;
    }

    public Class<?> getEventType() {
        return eventType;
    }

    public void setEventType(Class<?> eventType) {
        this.eventType = eventType;
    }
}

The foregoing analysis, so our class EventBus basic worded as follows:

package com.anonyper.annotationapplication.eventbus;

import android.os.Handler;
import android.os.Looper;

import com.anonyper.annotationapplication.bean.MethodBean;
import com.anonyper.annotationapplication.util.Loger;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * AnnotationApplication
 * Created by anonyper on 2019/6/6.
 */
public class EventBus {
    private static EventBus eventBus;

    private EventBus() {

    }

    public static EventBus getDefault() {
        synchronized (EventBus.class) {
            if (eventBus == null) {
                eventBus = new EventBus();
            }
        }
        return eventBus;
    }


    /**
     * 便于在主线程中发送消息
     */
    Handler handler = new Handler(Looper.getMainLooper());

    /**
     * 存储方法的容器
     */
    Map<Object, List<MethodBean>> methodBeanMap = new HashMap<>();

    /**
     * 针对每一个要发送消息存储对应的方法 便于查找
     */
    Map<String, List<MethodBean>> postMethodMap = new HashMap<>();

    /**
     * 注册对象
     *
     * @param object
     */
    public void register(Object object) {
        if (object != null) {
            List<MethodBean> methodBeanList = findMethodBean(object);
            if (methodBeanList != null) {
                methodBeanMap.put(object, methodBeanList);
            }
        }
    }


    /**
     * 取消注册对象
     *
     * @param object
     */
    public void unregister(Object object) {
        if (object != null && methodBeanMap.containsKey(object)) {
            List<MethodBean> methodBeanList = methodBeanMap.remove(object);
            for (MethodBean methodBean : methodBeanList) {
                String eventName = methodBean.getEventType().getName();
                removeEventMethod(eventName, methodBean);
                methodBean = null;
            }
            methodBeanList = null;
        }
    }

    /**
     * 根据对象找到标记了Subscribe注解的方法
     *
     * @param object
     * @return
     */
    private List<MethodBean> findMethodBean(Object object) {
        if (object == null) {
            return null;
        }
        List<MethodBean> methodBeanList = new ArrayList<>();
        //通过反射 获取该对象下面的所有方法,判断哪些是被特殊的注解标注了
        Class myclass = object.getClass();
        Method[] methods = myclass.getDeclaredMethods();//获取所有的方法 包括private的
        for (Method method : methods) {
            //获取Subscribe注解值
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                int count = method.getParameterCount();
                if (count <= 0) {
                    continue;
                }
            }
            //获取参数类型
            Class<?>[] parameterClasses = method.getParameterTypes();
            if (parameterClasses.length != 1) {
                continue;
            }
            //获取注解的信息
            Subscribe methodInfo = method.getAnnotation(Subscribe.class);
            if (methodInfo != null) {
                Class eventClass = parameterClasses[0];
                MethodBean methodBean = new MethodBean();
                methodBean.setObject(object);
                methodBean.setMethod(method);
                methodBean.setThreadMode(methodInfo.threadMode());
                methodBean.setEventType(eventClass);
                methodBeanList.add(methodBean);
                String eventName = eventClass.getName();
                addEventMethod(eventName, methodBean);
            }
        }
        return methodBeanList;
    }

    /**
     * 添加方法事件对应的方法
     *
     * @param eventName  要发送的消息名称
     * @param methodBean 该消息对饮的methodBean
     */
    private void addEventMethod(String eventName, MethodBean methodBean) {
        if (eventName == null || methodBean == null) {
            return;
        }
        if (!postMethodMap.containsKey(eventName)) {
            List<MethodBean> methodBeanList = new ArrayList<>();
            postMethodMap.put(eventName, methodBeanList);
        }
        List<MethodBean> methodBeanList = postMethodMap.get(eventName);
        if (methodBeanList == null) {
            methodBeanList = new ArrayList<>();
        }
        if (!methodBeanList.contains(methodBean)) {
            methodBeanList.add(methodBean);
        }

    }

    /**
     * 移除该对象的对应方法
     *
     * @param eventName
     * @param methodBean
     */
    private void removeEventMethod(String eventName, MethodBean methodBean) {
        if (eventName == null || methodBean == null) {
            return;
        }
        List<MethodBean> methodBeanList = postMethodMap.get(eventName);
        methodBeanList.remove(methodBean);
        if(methodBeanList.size()<=0){
            postMethodMap.remove(eventName);
            methodBeanList.clear();
            methodBeanList = null;
        }
    }


    /**
     * 找到监听了该对象的所有方法,然后执行方法
     *
     * @param object
     */
    public void post(Object object) {
        if (object != null) {
            List<MethodBean> methodBeanList = postMethodMap.get(object.getClass().getName());
            if (methodBeanList == null) {
                return;
            }
            for (MethodBean methodBean : methodBeanList) {
                Loger.i(methodBean.getMethod().getName());
                ThreadMode threadMode = methodBean.getThreadMode();
                if (threadMode == ThreadMode.MAIN) {
                    //主线程发送
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            invokeMethod(methodBean, object);
                        }
                    });
                } else {
                    //直接发送
                    invokeMethod(methodBean, object);
                }
            }
        }
    }

    /**
     * 执行发放
     *
     * @param methodBean
     * @param object     参数
     */
    void invokeMethod(MethodBean methodBean, Object object) {
        if (methodBean != null && object != null) {
            Method method = methodBean.getMethod();
            int modifiers = method.getModifiers();
            try {
                if (modifiers == Modifier.PRIVATE) {
                    method.setAccessible(true);
                }
                method.invoke(methodBean.getObject(), object);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

Activity in the use of:

package com.anonyper.annotationapplication;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.anonyper.annotation.TestAnnotation;
import com.anonyper.annotationapplication.bean.MessageEvent;
import com.anonyper.annotationapplication.eventbus.EventBus;
import com.anonyper.annotationapplication.eventbus.Subscribe;
import com.anonyper.annotationapplication.eventbus.ThreadMode;
import com.anonyper.annotationapplication.util.Loger;

/**
 * Eventbus 测试类
 */
public class EventBusActivity extends AppCompatActivity {
    public static final String TAG = "EventBusActivity >>> ";
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) this.findViewById(R.id.show_text);
        textView.setOnClickListener(o -> {
            EventBus.getDefault().post(new MessageEvent("这里是测试消息"));
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    /**
     * 私有方法
     *
     * @param messageEvent
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    private void testPrivateMethod(MessageEvent messageEvent) {
        Loger.i(TAG + " PrivateMethod >>> " + messageEvent.getMessage());
        textView.setText(messageEvent.getMessage());
    }

    /**
     * public方法
     *
     * @param messageEvent
     */
    @Subscribe(threadMode = ThreadMode.OTHER)
    public void testPublicMethod(MessageEvent messageEvent) {
        Loger.i(TAG + " PublicMethod >>> " + messageEvent.getMessage());

    }


    /**
     * 没有添加注解的方法
     *
     * @param messageEvent
     */
    public void publicMethod(MessageEvent messageEvent) {
        Loger.i(TAG + " 该方法不会被调用 >>> " + messageEvent.getMessage());
    }


}

Click Send Test results:

06-06 17:43:31.035 30025-30025/com.anonyper.annotationapplication I/Anonyper >>>: EventBusActivity >>>  PublicMethod >>> 这里是测试消息
06-06 17:43:31.035 30025-30025/com.anonyper.annotationapplication I/Anonyper >>>: EventBusActivity >>>  PrivateMethod >>> 这里是测试消息

to sum up

Methods used are reflected in EventBus Class, Method, etc., we have to list their specific knowledge:

Class Usage

Class class is used to record information for each object belongs to a class, it is unique. In the JVM load the required class, if not loaded through the object, ready to find .class file based on the class name, and then load it into the Class object.

Class no public constructor. Class object when loading classes are Java Virtual Machine and an automatic calling method defineClass configured by the class loader, it is not explicitly declared a Class object.

Create a Class object methods
  • Examples of the calling object .getClass () method
  • 使用Class.forName("com.XXX.XXX.ClassName")
  • A Java class Test.java class object is Test.class
Class Methods
  • forName (String classname)
    This method returns the name of the given string corresponding Class object.

  • getClassLoader ()
    Gets the class class loader.

  • the getComponentType ()
    if the current class represents an array, the array Class object representing the component returns, else return null.

  • getConstructor (Class [])
    Returns the specified public constructor object class Class object representation.

  • getConstructors ()
    Returns the class object array of all public constructors of this Class object.

  • getDeclaredConstructor (Class [])
    Returns the current object is designated a class constructor of the Class object already described.

  • getDeclaredConstructors ()
    returns an array of all the objects constructors already described this Class object class.

  • getDeclaredField (String)
    Returns a domain object class or interface currently designated Class object representation already described.

  • getDeclaredFields ()
    Returns the current Class object class or interface represented by an array of all domain objects already described.

  • getDeclaredMethod (String, Class [])
    Returns the current object is a method for the specified class or interface Class object has been described.

  • getDeclaredMethods ()
    array of all methods already described return Class objects represented by the class or interface.

  • getField (String)
    Returns the specified members of the public domain object class or interface of this Class object.

  • getFields ()
    Returns the class or interface Class object represented by an array of objects accessible to all public domain.

  • The getInterfaces ()
    returns an interface object represents the current class or interface implemented.

  • getMethod (String, Class [])
    Returns the class or interface of this Class object methods specified public member objects.

  • getMethods ()
    Returns the class represented by this Class object or interface method of the object array of all members of the public, and include methods inherited from the parent class declared.

  • getModifiers ()
    Returns the class or interface to modify the Java language code.

  • getName ()
    Returns the Class object types (classes, interfaces, group or array type) the full path name string.

  • getResource (String)
    Find a resource with the specified name.

  • getResourceAsStream (String)
    with a given name lookup resources.

  • getSigners ()
    to get a class mark.

  • getSuperclass ()
    if this object represents any one of a class Object addition, this object is returned parent class object.

  • isArray ()
    If this Class object represents an array returns true, otherwise returns false.

  • IsAssignableFrom (Class)
    determines whether the class or interface Class object represented by the same parameter or the same class specified Class interfaces, or parent class.

  • isInstance (Object)
    This method is the dynamic equivalent of the Java language instanceof operation.

  • isInterface ()
    determines whether the specified Class object represents an interface type.

  • isPrimitive ()
    determines whether the specified object is represented by a Java Class base type.

  • newInstance ()
    Creates a new instance of the class.

Method Usage

We can get to this Method Class object by class, then we can call the method to execute.

Method Method
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package java.lang.reflect;

import androidx.annotation.RecentlyNonNull;
import java.lang.annotation.Annotation;

public final class Method extends Executable {
    Method() {//构造方法
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public Class<?> getDeclaringClass() {//该方法的Class对象
        throw new RuntimeException("Stub!");
    }

    public String getName() {//方法名字
        throw new RuntimeException("Stub!");
    }

    public int getModifiers() {//修饰符
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public TypeVariable<Method>[] getTypeParameters() {//和这个类泛型有关吧,没太懂
        throw new RuntimeException("Stub!");
    }
  //List.class.getTypeParameters() 输出:E



    @RecentlyNonNull
    public Class<?> getReturnType() {//返回类型 Class对象
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public Type getGenericReturnType() {//返回类型 Type对象
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public Class<?>[] getParameterTypes() {//参数类型 Class数组
        throw new RuntimeException("Stub!");
    }

    public int getParameterCount() {//参数个数
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public Type[] getGenericParameterTypes() {//参数类型 Type数组
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public native Class<?>[] getExceptionTypes();//异常类型 Class数组

    @RecentlyNonNull
    public Type[] getGenericExceptionTypes() {//异常类型 Type数组
        throw new RuntimeException("Stub!");
    }

    public boolean equals(Object obj) {
        throw new RuntimeException("Stub!");
    }

    public int hashCode() {
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public String toString() {
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public String toGenericString() {//描述此方法的字符串,包括类型参数 示例:public void com.yiibai.SampleClass.setSampleField(java.lang.String)
        throw new RuntimeException("Stub!");
    }

    //反射调用该方法 传入参数var1 是该方法所属对象 var2 参数(可变形参)
    public native Object invoke(Object var1, Object... var2) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;

    public boolean isBridge() {//是否是桥接方法
        throw new RuntimeException("Stub!");
    }

    public boolean isVarArgs() {//是否是可变参数
        throw new RuntimeException("Stub!");
    }

    public boolean isSynthetic() {//是否是合成方法
        throw new RuntimeException("Stub!");
    }

    public boolean isDefault() {//该方法是否是一个注解的属性
        throw new RuntimeException("Stub!");
    }

    public native Object getDefaultValue();//返回注解的默认值
    //注解方法属性示例
    //public String stringValue() default "string default value";

    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {//返回指定注解信息
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public Annotation[] getDeclaredAnnotations() {//返回存在所有注解信息
        throw new RuntimeException("Stub!");
    }

    @RecentlyNonNull
    public Annotation[][] getParameterAnnotations() {//返回参数注解信息
        throw new RuntimeException("Stub!");
    }
}

Above, the code mainly in EventBus class, the address will hold git!

Reproduced in: https: //www.jianshu.com/p/0cbc43383b81

Guess you like

Origin blog.csdn.net/weixin_33713350/article/details/91074800