Welcome everyone to pay attention to my public number [old week chat architecture], The principle of Java backend mainstream technology stack, source code analysis, architecture and a variety of Internet high concurrency, high performance, high availability solutions.

What is Java reflection

Languages that allow program structure or variable types to be changed while the program is running are called dynamic languages. We don’t think of Java as a dynamic language, but it does have one dynamic correlation mechanism that stands out, commonly known as reflection.

As they say in the IT industry, there can be no framework without reflection, and existing frameworks are based on reflection. In actual project development, the framework is used most, and the class is filled most, and the concept of reflection is the blending agent that kneads the framework and class together. Therefore, reflection is the key to project development!

Second, the application and principle of reflection

We’ve probably heard of programs written in Java that compile once and run everywhere. This is why Java programs are platform-neutral, because Java source code is compiled into.class files called bytecodes wherever a Java Virtual machine (JVM) is installed. (Java provides a virtual mechanism on various platforms, and the first step is source code compilation by the Java IDE. In the second step, the Java bytecode is interpreted by the JVM to the target computer. In the third step, the target computer presents the results to us computer users. Therefore, Java is not a compilation mechanism, but an interpretation mechanism), and.class files are unimpeded.

Java’s reflection mechanism, which operates on this.class file, first loads the bytecode of the corresponding class (when you run Eclipse, the bytecode of the.class file is loaded into memory), and then reflects, or retrieves, the constructors, methods, and variables (fields) in the bytecode. Let’s start by defining a class Animal that defines constructors, methods, and variables:

package com.reflect;

public class Animal {

    public String name = "Dog";
    private int age = 30;

    // The default constructor takes no arguments
    public Animal(a) {
        System.out.println("Animal");
    }

    // Constructor with arguments
    public Animal(String name, int age) {
        System.out.println(name + "," + age);
    }

    Public method return type and parameter
    public String sayName(String name) {
        return "Hello,"+ name; }}Copy the code

Let’s define another test class: ReflectTest. Java

package com.reflect;

public class ReflectTest {
    public static void main(String[] args) {
        
        Animal animal = newAnimal(); System.out.println(animal.name); }}Copy the code

Let’s run our project and find the following:

Let’s use javap to see what the contents of this animal.class are:

D:\Tools\intellij idea\ideaIU_workspace\LeetCode\target\classes\com\reflect>java
p -c Animal.class
Compiled from "Animal.java"
public class com.reflect.Animal {
  public java.lang.String name;

  public com.reflect.Animal(a);Code:
       0: aload_0
       1: invokespecial/ / # 1Method java/lang/Object. "<init> : ()"V
       4: aload_0
       5: ldc/ / # 2String Dog
       7: putfield# 3 / /Field name:Ljava/lang/String;
      10: aload_0
      11: bipush        30
      13: putfield/ / # 4Field age:I
      16: getstatic# 5 / /Field java/lang/System.out:Ljava/
io/PrintStream;
      19: ldc# 6 / /String Animal
      21: invokevirtual# 7 / /Method java/io/PrintStream.printl
n: (Ljava/lang/String;)V
      24: return

  public com.reflect.Animal(java.lang.String.int);
    Code:
       0: aload_0
       1: invokespecial/ / # 1Method java/lang/Object. "<init> : ()"V
       4: aload_0
       5: ldc/ / # 2String Dog
       7: putfield# 3 / /Field name:Ljava/lang/String;
      10: aload_0
      11: bipush        30
      13: putfield/ / # 4Field age:I
      16: getstatic# 5 / /Field java/lang/System.out:Ljava/
io/PrintStream;
      19: new/ / # 8class java/lang/StringBuilder
      22: dup
      23: invokespecial# 9 / /Method java/lang/StringBuilder. "<init> : ()"V
      26: aload_1
      27: invokevirtual# 10 / /Method java/lang/StringBuilder.ap
pend: (Ljava/lang/String;)Ljava/lang/StringBuilder;
      30: ldc/ / # 11String ,
      32: invokevirtual# 10 / /Method java/lang/StringBuilder.ap
pend: (Ljava/lang/String;)Ljava/lang/StringBuilder;
      35: iload_2
      36: invokevirtual# 12 / /Method java/lang/StringBuilder.ap
pend: (I)Ljava/lang/StringBuilder;
      39: invokevirtual# 13 / /Method java/lang/StringBuilder.to
String: ()Ljava/lang/String;
      42: invokevirtual# 7 / /Method java/io/PrintStream.printl
n: (Ljava/lang/String;)V
      45: return

  public java.lang.String sayName(java.lang.String);
    Code:
       0: new/ / # 8class java/lang/StringBuilder
       3: dup
       4: invokespecial# 9 / /Method java/lang/StringBuilder. "<init> : ()"V
       7: ldc# 14 / /String Hello,
       9: invokevirtual# 10 / /Method java/lang/StringBuilder.ap
pend: (Ljava/lang/String;)Ljava/lang/StringBuilder;
      12: aload_1
      13: invokevirtual# 10 / /Method java/lang/StringBuilder.ap
pend: (Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: invokevirtual# 13 / /Method java/lang/StringBuilder.to
String: ()Ljava/lang/String;
      19: areturn
}
Copy the code

The bytecode contains Animal constructors, variables, and methods, but all are of public type. Private int age =30 Of course, since it is a private part of the class, it is certainly not exposed, but it does not prevent us from obtaining private members of the bytecode through reflection. (This article only demonstrates private variables (field).

Our Animal class is defined in anima. Java, but in the animal. class file our Animal class is stated as follows:

public class com.reflect.Animal
Copy the code

We will use reflection to load a class from a.class file and parse out the contents (constructors, properties, methods) of the corresponding class in bytecode:

ReflectTest.java:

package com.reflect;

import java.lang.reflect.Constructor;

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

        // Load the class and specify the fully qualified name of the class: package name + class name
        Class c1 = Class.forName("com.reflect.Animal");
        System.out.println(c1); // Prints c1 and finds that the value is the same as the class name in the bytecode

        // open the null constructor for c1
        Constructor ctor1 = c1.getConstructor();

        // The purpose of the constructor is to create an instance of the class
        // Only private constructors can be used to create instances of a class.
        // ctor1.newinstance () generates an Object by default. We need to convert it to the Animal class we want
        Animal a1 = (Animal) ctor1.newInstance();

        // a1 is an instance of AnimalSystem.out.println(a1.name); }}Copy the code
Class com.reflect.Animal Animal DogCopy the code

There are two ways to get variables (fields) and methods in the class. One is getXXX, and the other is getDeclaredXXX. There are differences between them. To get the corresponding instance field value and invoke method (equivalent to executing an instance method), let’s take a look at the full demo:

An enhanced version of ReflectTest. Java

package com.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

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

        System.out.println("A(no-argument constructor)-- load class, reflect class constructor, use constructor new Animal instance--");

        // Load the class and specify the fully qualified name of the class: package name + class name
        Class c1 = Class.forName("com.reflect.Animal");
        System.out.println(c1); // Prints c1 and finds that the value is the same as the class name in the bytecode

        // open the null constructor for c1
        Constructor ctor1 = c1.getConstructor();

        // The purpose of the constructor is to create an instance of the class
        // Only private constructors can be used to create instances of a class.
        // ctor1.newinstance () generates an Object by default. We need to convert it to the Animal class we want
        Animal a1 = (Animal) ctor1.newInstance();

        // a1 is an instance of Animal
        System.out.println(a1.name);

        System.out.println("A(constructor with arguments)-- load class, reflect class constructor, use constructor new Animal instance--");

        //2.b, public constructor for c1, string and int
        Constructor ctor2 = c1.getConstructor(String.class, int.class);
        Animal a2 = (Animal) ctor2.newInstance("cat".20);

        System.out.println("B-- get all the fields in this class ----------------------------");

        Public, private, and protected fields, excluding those declared in the parent class
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("C-- get all public fields in this class, and get the field value of the specified object -----");

        // get all the public fields in the class
        fields = c1.getFields();
        for (Field field : fields) {
            System.out.println(field + ", field value =" + field.get(a1));
            // Note that the value is private and cannot be obtained via field.get(a1)
            // Change the value of name by reflecting the class field name (note that the original value in the class name="Dog")
            // If the field name is equal to "name" and the field type is String, we change the value of the field, that is, the value of the class variable name
            if (field.getName() == "name" && field.getType().equals(String.class)) {
                String name_new = (String) field.get(a1); // Remember to convert the type
                name_new = "Husky"; // reassign name
                field.set(a1, name_new); // Set the name value of the current instance a1 to take effect
            }
        }

        System.out.println("Use the reflected field, modify the field value, modified name ="+a1.name);
        System.out.println("D-- Get all the methods in this class --------------------");

        Public, private, and protected methods, excluding methods declared in the parent class
        Method[] methods = c1.getDeclaredMethods();
        for (Method m : methods) {
            System.out.println(m);// We define only one public method in the Animal class, sayName
        }

        System.out.println("E-- Get all public methods in this class, including the parent class and all public methods in the implementation interface -----------");

        Get all public methods in the class, including all public methods in the parent class and in the implementation interface
        methods = c1.getMethods();
        for (Method m : methods) {
            System.out.println(m);// We define only one public method in the Animal class, sayName
        }

        System.out.println("F-- gets the specified method based on the method name and parameter type, and evokes the method: specify object A1 and assign the corresponding parameter -----------");

        GetMethod: the first argument is the name of the Method, followed by the class of the Method parameters
        Method sayName = c1.getMethod("sayName", String.class);
        System.out.println(sayName.invoke(a1, "riemann")); }}Copy the code
Output result: A(no-argument constructor)-- load class, reflect class constructor, use constructor new Animal instance-- class com.reflect.Animal Animal Dog A (have arguments constructor) - load, reflection of constructors, use A Animal instance constructor new instance -- cat, 20 - get all the fields in this class B -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the public Java.lang.String com.reflect.animal. name private int com.reflect.animal. age C-- ----- public java.lang.string com.reflect.animals. name, = Dog Modified name = huskies D - get all of the methods in this class -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the public Java lang. String com. Reflect. Animal. SayName (Java. Lang. String) E-- Get all public methods in this class, Including a parent class and interface to realize the all public methods -- -- -- -- -- -- -- -- -- -- - public Java. Lang. String com. Reflect. Animal. The sayName (Java. Lang. String) public final void  java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void Java.lang.object. NotifyAll () F - get specified method according to the method name and argument types, and arouse method: specify the Object belongs to a1, and gives corresponding parameter assignment -- -- -- -- -- -- -- -- -- -- - Hello, RiemannCopy the code

Reflection works by loading the corresponding class in the bytecode and then, depending on the information of the loaded class, disentangle the contents of the class bit by bit, whether you are public or private, or of the class itself, or the method from the original inheritance or implementation interface. Our Reflection technology in Java reflects, We can pull it back out of the bytecode, not only can we get the name of the field, we can get the value of the field and we can change the value of the field, not only can we get the declaration of the method but we can also get the definition of the method and the invocation method, and of course, you’re wondering, right?

Why is it so easy to create an object using newInstance, a reflection technique?

Why do I have to use reflection to get the name field when I can access a variable directly from a1.

Why do I have to use reflection when I can do it in a few lines of code?

Ok, before we decipher the answer, let’s think about a question, right?

Suppose we define a number of classes, Animal, Person, Car… If I want an Animal instance, I’m new Animal (). If another Person wants a Person instance, he needs new Person (). Of course, the other Person says, I just want a Car instance, so he wants new Car ()… As a result, each user has different object requirements for new, so they have to modify the source code and recompile to make it work. This method of writing new objects to code is very inflexible, so to avoid this method, Java provides a reflection mechanism, typical applications are as follows:

For example, in Spring we often see:

How does Spring help us instantiate objects and put them into containers for this configuration? Yes, by reflection !!!!

Let’s take a look at the following pseudo-code implementation process:

		// parse 
       The id attribute of the element gives the string value "sqlSessionFactory"
	    String idStr = "sqlSessionFactory";  
	    // parse 
      
        element's class attribute to get the string value of "org. Mybatis. Spring. SqlSessionFactoryBean"
      
	    String classStr = "org.mybatis.spring.SqlSessionFactoryBean";  
	    // Use reflection knowledge to get the Class object through classStr
	    Class cls = Class.forName(classStr);  
	    // instantiate the object
	    Object obj = cls.newInstance();  
	    // Container Indicates the Spring container
	    container.put(idStr, obj);  
		
	    // When an object of another class is needed in a class, we proceed
	    
	    // parse 
       The name attribute of the element gets the string value "dataSource"
	    String nameStr = "dataSource";  
	    // parse 
       The ref attribute of the element yields the string value "dataSource"
	    String refStr = "dataSource";  
	    // Generate the name of the setter method to call
	    String setterName = "set" + nameStr.substring(0.1).toUpperCase()  
	            + nameStr.substring(1);  
	    // Get the spring container Bean named refStr, which will be passed in as an argument
	    Object paramBean = container.get(refStr);  
	    // Get the Method Class of the setter Method, where CLS is the Class object from the reflection code
	    Method setter = cls.getMethod(setterName, paramBean.getClass());  
	    // Call the invoke() method, where obj is the Object from the reflection code
	    setter.invoke(obj, paramBean); 
Copy the code

It’s pseudocode, but it’s the same reflection mechanism that we used in this article. Now you know where our reflection mechanism is used. Yes, it’s in the Java Web framework that we often talk about. Whenever you see the fully qualified name of a class (package name + class name) in your code or configuration file, the underlying principle basically uses Java’s reflection mechanism.

So, if you don’t do a framework, you basically don’t use reflection, and we’re mostly on the framework side, and reflection is already implemented at the bottom, so we don’t have to worry about writing that complicated code. However, we must understand that this mechanism exists!

There are three ways to create class instances

JavaBean

public class Person implements China{
      private String name;
      private int age ;
      private char sex ;

      public Person(a) {
           super(a); }public Person(String name, int age, char sex) {
           super(a);this .name = name;
           this .age = age;
           this .sex = sex;
     }

      public String getName(a) {
           return name ;
     }

      public void setName(String name) {
           this .name = name;
     }

      public int getAge(a) {
           return age ;
     }

      public void setAge(int age) {
           this .age = age;
     }

      public char getSex(a) {
           return sex ;
     }

      public void setSex(char sex) {
           this .sex = sex;
     }
      public void eat(a)
     {
          System. out .println("Eat" );
     }

      @Override
      public String toString(a) {
           return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]" ;
     }

      @Override
      public void sayChina(a) {
           // TODO Auto-generated method stub
          System. out .println("Author:" + AUTHOR + "Nationality:"+ NATIONAL );
     }

      @Override
      public String sayHello(String name, int age, char sex) {
           // TODO Auto-generated method stub
           return "Name:" + name + "Age:"+ age + "Gender."+ sex; }}Copy the code
public class ClassDemo {

     public static void main(String[] args) {
          Person p1 = new Person("Xiao Ming" ,20.'male' );
          Person p2 = new Person("Little red" ,23.'woman' );

           GetClass ()), get the bytecode file from the Person Class
           Class class1 = p1.getClass();
          System. out.println(p1.getClass().getName());
           Class class2 = p2.getClass();
          System. out.println(class1 == class2 );

          System. out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =" );
           Class: You need to enter an explicit Class, and each type has a static Class attribute.
           Class class3 = Person.class;
          System. out.println(class1 == class2);

          System. out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =" );
           // Create a Class object: (forName(): just pass it as a string)
           Return a Class object via a static forName (String className) method of the Class Class. ClassName must be the full path name;
           // Class.forname () has an exception: ClassNotFoundException

           Class class4 = null;
           try {
              class4 = Class.forName("cn.itcast.Person");
          } catch (ClassNotFoundException e) {
               // TODO Auto-generated catch blocke.printStackTrace(); } System. out.println(class4 == class3); }}Copy the code

Note: the third method is generally used in development, because the third method receives a string path, which can be obtained through the configuration file in the future, and has good generality;