Explain Java reflection mechanism in detail

Posted by mrdonrule on Sun, 23 Jan 2022 06:45:01 +0100

Explain Java reflection mechanism in detail

Experience the benefits of reflection through cases

case

  • US group take away - > payment - either paid with WeChat or paid by Alipay.
//Interface maker: meituan takeout
public interface Mtwm {
    //Online payment function:
    void payOnline();
}
public class WeChat implements Mtwm{
    @Override
    public void payOnline() {
        //Specific functions of wechat payment:
        System.out.println("I have ordered takeout and am using wechat to pay");
    }
}
public class AliPay implements Mtwm {
    @Override
    public void payOnline() {
        //Specific Alipay payment:
        System.out.println("I have ordered takeaway, I am using Alipay to pay for it.");
    }
}
public class BankCard implements Mtwm{
    @Override
    public void payOnline() {
        System.out.println("I've ordered takeout. I'm paying with China Merchants Bank credit card");
    }
}
  • Test class
public class Test {
    public static void main(String[] args) {
        //Define a string to simulate the foreground payment method:
        String str = "WeChat";
        if("WeChat".equals(str)){//str.equals("wechat") ----? Avoid null pointer exceptions
            //Wechat payment:
            //new WeChat().payOnline();
            pay(new WeChat());
        }
        if("Alipay".equals(str)){
            //Alipay payment:
            //new AliPay().payOnline();
            pay(new AliPay());
        }
        if("China Merchants Bank".equals(str)){
            pay(new BankCard());
        }
    }
    //Wechat payment
    public static void pay(WeChat wc){
        wc.payOnline();
    }
    //Alipay payment
    public static void pay(AliPay ap){
        ap.payOnline();
    }
    //Payment by China Merchants Bank
    public static void pay(BankCard bc){
        bc.payOnline();
    }
}

In order to improve the extensibility of code -- object-oriented characteristics: polymorphism

public class Test {
    public static void main(String[] args) {
        //Define a string to simulate the foreground payment method:
        String str = "WeChat";
        if("WeChat".equals(str)){//str.equals("wechat") ----? Avoid null pointer exceptions
            //Wechat payment:
            pay(new WeChat());
        }
        if("Alipay".equals(str)){
            //Alipay payment:
            pay(new AliPay());
        }
        if("China Merchants Bank".equals(str)){
            pay(new BankCard());
        }
    }
    //A method parameter is an interface. What is passed in is the object of the implementation class of the interface -- a form of polymorphism
    public static void pay(Mtwm m){
        m.payOnline();
    }

}
  • Polymorphism can indeed improve the scalability of code, but: the scalability is not the best.
  • Why not achieve the best: the above branches still need to be deleted or added manually.
  • Solution: reflection mechanism

Use reflection to achieve the above functions:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo {
    public static void main(String[] args) throws Exception {
        //Define a string to simulate the foreground payment method:
        String str = "com.zhaoss.test01.AliPay";  //String: actually: it is the fully qualified path of wechat class
        //The following code uses reflection:
        Class  cls = Class.forName(str);//CLS -- > class specific object -- AliPay bytecode information
        Object o = cls.newInstance();
        Method method = cls.getMethod("payOnline");
        method.invoke(o);
    }
}

Re experience reflection through concept

reflex

  • JAVA reflection mechanism is to know all the properties and methods of any class in the running state; For any object,

  • Can call any of its methods and properties; This function of dynamically obtaining information and dynamically calling object methods is called the reflection mechanism of java language.

  • When bytecode files are generated after compilation, the class loader subsystem is responsible for loading class files from the file system through binary byte stream.

  • When executing the program (java.exe), read the bytecode file into the JVM - > this process is called Class loading. Then create a Java. Net in memory Lang. Class object – > this object will be put into the bytecode information. This Class object will load the bytecode information accordingly. This object will be used as an external interface for the program to access various data of this Class in the method area.

  • So: we can see the structure of the class through this object. This object is like a mirror. We can see all kinds of information of the class through the mirror. We vividly call it reflection

  • The ability of the program to examine its self is called introspection. Reflection and introspection are two terms often mentioned together.

Note: during operation, if we want to generate a Class object, the Java virtual machine (JVM) will check whether the Class object of this type has been loaded.
If it is not loaded, the JVM will find it based on the name of the class Class file and load it. Once a class object of a type has been loaded into memory, it can be used to generate all objects of that type.

Supplement:

Dynamic language vs static language

1. Dynamic language

  • Is a kind of language whose structure can be changed at run time: for example, new functions, objects, and even code can
    When introduced, existing functions can be deleted or other structural changes. Generally speaking, it's transportation
    Line time code can change its structure according to certain conditions.
  • Main dynamic languages: Object-C, c#, JavaScript, PHP, Python, Erlang.

2. Static language

  • Corresponding to dynamic language, the language with immutable runtime structure is static language. Such as Java, C, C + +.
  • So Java is not a dynamic language, but Java can be called "quasi dynamic language". That is, Java has certain dynamics. We can use reflection mechanism and bytecode operation to obtain characteristics similar to dynamic language.
  • The dynamic nature of Java makes programming more flexible!

Class understanding

Create class

//As a parent class
public class Person {
    //attribute
    private int age;
    public String name;
    //method
    private void eat(){
        System.out.println("Person---eat");
    }
    public void sleep(){
        System.out.println("Person---sleep");
    }
}
//Student as a subclass
public class Student extends Person {
    //Properties:
    private int sno;//Student number
    double height;//height
    protected double weight;//weight
    public double score;//achievement
    //method:
    public String showInfo(){
        return "I am a three good student";
    }
    private void work(){
        System.out.println("I will look for a job in the future-->Become coder programmer ape program yuan");
    }
    //constructor 
    public Student(){
        System.out.println("Null parameter constructor");
    }
    private Student(int sno){
        this.sno = sno;
    }
    Student(int sno,double weight){
        this.sno = sno;
        this.weight = weight;
    }
}

Method for obtaining bytecode

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //Case: take the bytecode information of Person as an example
        //Method 1: get through getClass() method
        Person p = new Person();
        Class c1 = p.getClass();
        System.out.println(c1);
        //Method 2: through the built-in class attribute:
        Class c2 = Person.class;
        System.out.println(c2);
        System.out.println(c1==c2);
        //Note: mode 1 and mode 2 are not commonly used
        //Method 3: -- "used most: call the static method forName provided by Class class
        Class c3 = Class.forName("com.zhaoss.test02.Person");
        //Method 4: use class loader (understand skill points)
        ClassLoader loader = Test.class.getClassLoader();
        Class c4 = loader.loadClass("com.zhaoss.test02.Person");
    }
}

The type that can be used as an instance of Class

Class

(1) Class: external class, internal class
(2) Interface
(3) Annotation
(4) Array
(5) Basic data type
(6)void

verification

public class Demo {
    public static void main(String[] args) {
        /*
        Class Class:
        (1)Class: external class, internal class
        (2)Interface
        (3)annotation
        (4)array
        (5)Basic data type
        (6)void
         */
        Class c1 = Person.class;
        Class c2 = Comparable.class;
        Class c3 = Override.class;
        int[] arr1 = {1,2,3};
        Class c4 = arr1.getClass();
        int[] arr2 = {5,6,7};
        Class c5 = arr2.getClass();
        System.out.println(c4==c5);//Result: true The same bytecode is obtained for the same dimension and element type
        
        Class c6 = int.class;
        Class c7 = void.class;
    }
}

Supplement and improve the previous class

//As a parent class
public class Person implements Serializable {
    //attribute
    private int age;
    public String name;
    //method
    private void eat(){
        System.out.println("Person---eat");
    }
    public void sleep(){
        System.out.println("Person---sleep");
    }
}
//Student as a subclass
@MyAnnotation(value="hello")
public class Student extends Person implements MyInterface{
    //Properties:
    private int sno;//Student number
    double height;//height
    protected double weight;//weight
    public double score;//achievement
    //method:
    @MyAnnotation(value="himethod")
    public String showInfo(){
        return "I am a three good student";
    }
    public String showInfo(int a,int b){
        return "Overloading methods ====I am a three good student";
    }
    private void work(){
        System.out.println("I will look for a job in the future-->Become coder programmer ape program yuan");
    }
    void happy(){
        System.out.println("The most important thing in life is to be happy every day");
    }
    protected int getSno(){
        return sno;
    }
    //constructor 
    public Student(){
        System.out.println("Null parameter constructor");
    }
    private Student(int sno){
        this.sno = sno;
    }
    Student(int sno,double weight){
        this.sno = sno;
        this.weight = weight;
    }
    protected Student(int sno,double height,double weight){
        this.sno = sno;
    }
    @Override
    @MyAnnotation(value="hellomyMethod")
    public void myMethod() {
        System.out.println("I rewritten it myMethod method..");
    }
    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", height=" + height +
                ", weight=" + weight +
                ", score=" + score +
                '}';
    }
}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
/*
@Target:Defines which elements in the program can be modified by the current annotation
@Retention:Define the declaration period of the annotation
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();//attribute
}

public interface MyInterface {//Custom interface
    //Define any abstract method:
    void myMethod();
}

Get constructor and create object

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test01 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //Get bytecode information:
        Class cls = Student.class;
        //The constructor can be obtained from bytecode information:
        //getConstructors can only get the public decorated constructor of the current runtime class
        Constructor[] c1 = cls.getConstructors();
        for(Constructor c:c1){
            System.out.println(c);
        }
        System.out.println("-------------------");
        //Getdeclaraedconstructors: constructor that gets all modifiers of the runtime class
        Constructor[] c2 = cls.getDeclaredConstructors();
        for(Constructor c:c2){
            System.out.println(c);
        }
        System.out.println("-------------------");
        //Gets the specified constructor:
        //Get empty constructor
        Constructor con1 = cls.getConstructor();
        System.out.println(con1);
        //A parametric constructor that gets two parameters:
        Constructor con2 = cls.getConstructor(double.class, double.class);
        System.out.println(con2);
        //Get a parameter constructor: and it is private decorated
        Constructor con3 = cls.getDeclaredConstructor(int.class);
        System.out.println(con3);
        //With the constructor, I can create objects:
        Object o1 = con1.newInstance();
        System.out.println(o1);
        Object o2 = con2.newInstance(180.5, 170.6);
        System.out.println(o2);
    }
}

Get properties and assign values

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test02 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        //Get bytecode information of runtime class:
        Class cls = Student.class;
        //Get properties:
        //getFields: get the public modified attributes in the runtime class and parent class
        Field[] fields = cls.getFields();
        for(Field f:fields){
            System.out.println(f);
        }
        System.out.println("---------------------");
        //Getdeclaraedfields: get all properties in the runtime class
        Field[] declaredFields = cls.getDeclaredFields();
        for(Field f:declaredFields){
            System.out.println(f);
        }
        System.out.println("---------------------");
        //Get the specified property:
        Field score = cls.getField("score");
        System.out.println(score);
        Field sno = cls.getDeclaredField("sno");
        System.out.println(sno);
        System.out.println("---------------------");
        //Specific structure of attribute:
        //Get modifier
        /*int modifiers = sno.getModifiers();
        System.out.println(modifiers);
        System.out.println(Modifier.toString(modifiers));*/
        System.out.println(Modifier.toString(sno.getModifiers()));
        //Get the data type of the property:
        Class clazz = sno.getType();
        System.out.println(clazz.getName());
        //Get the name of the property:
        String name = sno.getName();
        System.out.println(name);
        System.out.println("-------------------------------");
        //Assign a value to the attribute: (set a value to the attribute, there must be an object)
        Field sco = cls.getField("score");
        Object obj = cls.newInstance();
        sco.set(obj,98);//Set a specific value for the score attribute of obj object, which is 98
        System.out.println(obj);
    }
}

Get the method and call

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test03 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //Get bytecode information:
        Class cls = Student.class;
        //Acquisition method:
        //getMethods: get the methods of the runtime class and all the methods in the parent class (modified by public)
        Method[] methods = cls.getMethods();
        for(Method m:methods){
            System.out.println(m);
        }
        System.out.println("-----------------------");
        //Getdeclaraedmethods: get all methods in the runtime class:
        Method[] declaredMethods = cls.getDeclaredMethods();
        for(Method m:declaredMethods){
            System.out.println(m);
        }
        System.out.println("-----------------------");
        //Get the specified method:
        Method showInfo1 = cls.getMethod("showInfo");
        System.out.println(showInfo1);
        Method showInfo2 = cls.getMethod("showInfo", int.class, int.class);
        System.out.println(showInfo2);
        Method work = cls.getDeclaredMethod("work",int.class);
        System.out.println(work);
        System.out.println("-----------------------");
        //Specific structure of acquisition method:
        /*
        @annotation
        Modifier return value type method name (parameter list) throws XXXXX {}
         */
        //name:
        System.out.println(work.getName());
        //Modifier:
        int modifiers = work.getModifiers();
        System.out.println(Modifier.toString(modifiers));
        //Return value:
        System.out.println(work.getReturnType());
        //Parameter list:
        Class[] parameterTypes = work.getParameterTypes();
        for(Class c:parameterTypes){
            System.out.println(c);
        }
        //Get comments:
        Method myMethod = cls.getMethod("myMethod");
        Annotation[] annotations = myMethod.getAnnotations();
        for(Annotation a:annotations){
            System.out.println(a);
        }
        //Get exception:
        Class[] exceptionTypes = myMethod.getExceptionTypes();
        for(Class c:exceptionTypes){
            System.out.println(c);
        }
        //Call method:
        Object o = cls.newInstance();
        myMethod.invoke(o);//Call the mymethod method method of the o object
        System.out.println(showInfo2.invoke(o,12,45));;
    }
}

Get the package, interface and comments of the class

import java.lang.annotation.Annotation;
public class Test04 {
    public static void main(String[] args) {
        //Get bytecode information:
        Class cls = Student.class;
        //Get the interface of the runtime class:
        Class[] interfaces = cls.getInterfaces();
        for(Class c:interfaces){
            System.out.println(c);
        }
        //Get the interface of the parent class:
        //Get the bytecode information of the parent class first:
        Class superclass = cls.getSuperclass();
        //Get interface:
        Class[] interfaces1 = superclass.getInterfaces();
        for(Class c:interfaces1){
            System.out.println(c);
        }
        //Get the package where the runtime class is located:
        Package aPackage = cls.getPackage();
        System.out.println(aPackage);
        System.out.println(aPackage.getName());
        //Get the annotation of the run class:
        Annotation[] annotations = cls.getAnnotations();
        for(Annotation a:annotations){
            System.out.println(a);
        }
    }
}

Topics: Java Back-end JavaSE