In depth analysis of Java reflection mechanism

  • 2020-04-01 04:21:49
  • OfStack

Java reflection mechanism is in the running state, for any class, can know all the attributes and methods of the class; For any object, you can call any of its methods and properties. This ability to dynamically retrieve information and dynamically invoke methods on objects is called the Java language's reflection mechanism. The concept of reflection, first proposed by Smith in 1982, refers primarily to the ability of a program to access, detect, and modify its own state or behavior. This concept soon led to the study of applied reflexivity in computer science. It was first adopted by the programming language design field, and has made great achievements in Lisp and object orientation. Of course, reflection itself is not a new concept. It may remind us of the concept of reflection in optics. Although computer science gives new meaning to the concept of reflection, they do have certain similarities in terms of phenomena, which help us to understand.

          The Java reflection mechanism mainly provides the following USES:

Determines the class to which any object belongs at run time

Constructs an object of any class at run time

Determines at runtime which member variables and methods any class has

Calls methods on any object at run time

Let's start with a simple example to understand how Java's reflection mechanism works.


package com.wanggc.reflection;
import java.lang.reflect.Method;

public class ForNameTest {
  
  public static void main(String[] args) throws Exception {
    //For the Class
    Class<?> cls = Class.forName(args[0]);
    //Method to get the corresponding object by Class
    Method[] methods = cls.getMethods();
    //Output each method name
    for (Method method : methods) {
      System.out.println(method);
    }
  }
}

          When the parameter passed in is java.lang.string, the following result is printed


public boolean java.lang.String.equals(java.lang.Object)
public java.lang.String java.lang.String.toString()
public int java.lang.String.hashCode()
public int java.lang.String.compareTo(java.lang.String)
public int java.lang.String.compareTo(java.lang.Object)
public int java.lang.String.indexOf(int)
public int java.lang.String.indexOf(int,int)
public int java.lang.String.indexOf(java.lang.String)
public int java.lang.String.indexOf(java.lang.String,int)
public static java.lang.String java.lang.String.valueOf(int)
public static java.lang.String java.lang.String.valueOf(char)
public static java.lang.String java.lang.String.valueOf(boolean)
public static java.lang.String java.lang.String.valueOf(float)
public static java.lang.String java.lang.String.valueOf(char[],int,int)
public static java.lang.String java.lang.String.valueOf(double)
public static java.lang.String java.lang.String.valueOf(char[])
public static java.lang.String java.lang.String.valueOf(java.lang.Object)
public static java.lang.String java.lang.String.valueOf(long)
public char java.lang.String.charAt(int)
public int java.lang.String.codePointAt(int)
public int java.lang.String.codePointBefore(int)
public int java.lang.String.codePointCount(int,int)
public int java.lang.String.compareToIgnoreCase(java.lang.String)
public java.lang.String java.lang.String.concat(java.lang.String)
public boolean java.lang.String.contains(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.StringBuffer)
public static java.lang.String java.lang.String.copyValueOf(char[])
public static java.lang.String java.lang.String.copyValueOf(char[],int,int)
public boolean java.lang.String.endsWith(java.lang.String)
public boolean java.lang.String.equalsIgnoreCase(java.lang.String)
public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])
public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[])
public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException
public void java.lang.String.getBytes(int,int,byte[],int)
public byte[] java.lang.String.getBytes()
public byte[] java.lang.String.getBytes(java.nio.charset.Charset)
public void java.lang.String.getChars(int,int,char[],int)
public native java.lang.String java.lang.String.intern()
public boolean java.lang.String.isEmpty()
public int java.lang.String.lastIndexOf(java.lang.String)
public int java.lang.String.lastIndexOf(int,int)
public int java.lang.String.lastIndexOf(int)
public int java.lang.String.lastIndexOf(java.lang.String,int)
public int java.lang.String.length()
public boolean java.lang.String.matches(java.lang.String)
public int java.lang.String.offsetByCodePoints(int,int)
public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int)
public boolean java.lang.String.regionMatches(int,java.lang.String,int,int)
public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence)
public java.lang.String java.lang.String.replace(char,char)
public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String)
public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String,int)
public boolean java.lang.String.startsWith(java.lang.String)
public boolean java.lang.String.startsWith(java.lang.String,int)
public java.lang.CharSequence java.lang.String.subSequence(int,int)
public java.lang.String java.lang.String.substring(int)
public java.lang.String java.lang.String.substring(int,int)
public char[] java.lang.String.toCharArray()
public java.lang.String java.lang.String.toLowerCase()
public java.lang.String java.lang.String.toLowerCase(java.util.Locale)
public java.lang.String java.lang.String.toUpperCase()
public java.lang.String java.lang.String.toUpperCase(java.util.Locale)
public java.lang.String java.lang.String.trim()
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
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 java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

          This lists all the method names of the java.lang.string class, their qualifiers, return types, and exceptions thrown. This program USES the Class Class forName method to load the specified Class, and then calls the getMethods method to return a list of methods for the specified Class. Java.lang.reflect.method is used to express a single Method in a class.

          Using Java's reflection mechanism, there are generally three steps to follow:

Get the Class object that you want to manipulate
The Class object obtained in the first step gets the method or property name of the action Class
Operates on the method or property obtained in the second step

        When Java runs, no matter how many objects a Class generates, they all correspond to the same Class object, which represents the classes and interfaces in the running program. There are three common ways to get the Class object of an action Class:

Call the static method forName of Class, as in the example above;

Use the.class syntax of a class, such as Class< The & # 63; > CLS = String. The class;
Call the getClass method of the object, such as String STR = "ABC"; Class< The & # 63; > CLS = STR. GetClass ();

          Here is an example of how to execute a method of an object through the three steps described above:


 package com.wanggc.reflection;
 import java.lang.reflect.Method;
 
 public class ReflectionTest {
   public static void main(String[] args) throws Exception {
     DisPlay disPlay = new DisPlay();
     //For the Class
     Class<?> cls = disPlay.getClass();
     //Get the show method of the DisPlay Class by Class
     Method method = cls.getMethod("show", String.class);
     //Call the show method
     method.invoke(disPlay, "Wanggc");
   }
 }
 class DisPlay {
   public void show(String name) {
     System.out.println("Hello :" + name);
   }
 }

          As mentioned earlier, each Class in a Java program has a Class object corresponding to it. The first step in Java reflection is to get the Class object, such as line 14. Of course, there must also be a Method object corresponding to the Method of each class. To invoke the Method by reflection, you first get the Method object of the Method, such as line 16, and then use the Method object to invoke the Method in reverse, such as line 18. Note that the first parameter of the getMethod method on line 16 is the method name, and the second is the parameter type of the method. If there are more than one parameter, then add the parameter, because getMethod is a variable-parameter method. The invoke method, which executes 18 lines of code, is actually just executing the show method, and notice that the first argument of the invoke is an object of the DisPlay class, which is the show method of which object of the DisPlay class is called, and the second argument is the argument passed to the show method. The type and number must always be along with the 16-line getMethod method.

          The above example shows how to call a method of a class by reflection. The following example shows how to assign a property of a class by reflection:


 package com.wanggc.reflection;
  import java.lang.reflect.Field;
  
 public class ReflectionTest {
   public static void main(String[] args) throws Exception {
     //Create student objects
     Student student = new Student();
     //Assign a value to the student object
     student.setStuName("Wanggc");
     student.setStuAge();
     //Create a copy of the target object
     Student destStudent = new Student();
     //Copy student object
     copyBean(student, destStudent);
     //Output copy result
     System.out.println(destStudent.getStuName() + ":"
         + destStudent.getStuAge());
   }
   
   private static void copyBean(Object from, Object dest) throws Exception {
     //Gets the Class object that copies the source object
     Class<?> fromClass = from.getClass();
     //Gets the property list of the copied source object
     Field[] fromFields = fromClass.getDeclaredFields();
     //Gets the Class object that copies the target object
     Class<?> destClass = dest.getClass();
     Field destField = null;
     for (Field fromField : fromFields) {
       //Gets the property name of the copy source object
       String name = fromField.getName();
       //Gets a property that copies the same name of the target object
       destField = destClass.getDeclaredField(name);
       //Sets the accessibility of the properties
       fromField.setAccessible(true);
       destField.setAccessible(true);
       //Assigns the value of a property of the copy source object to the corresponding property of the copy target object
       destField.set(dest, fromField.get(from));
     }
   }
 }
 
 class Student {
   
   private String stuName;
   
   private int stuAge;
   
   public String getStuName() {
     return stuName;
   }
   
   public void setStuName(String stuName) {
     this.stuName = stuName;
   }
   
   public int getStuAge() {
     return stuAge;
   }
   
   public void setStuAge(int stuAge) {
     this.stuAge = stuAge;
   }
 }

            In Java's emission mechanism, classes have Class correspondence, methods of classes have Method correspondence, and of course, attributes also have Field correspondence. The comments in the code have been commented in detail and won't be repeated here. Note, however, that Field provides the get and set methods to get and set the value of the property, but since the property is of a private type, you need to set the accessibility of the property to true, as in lines 50 to 51. Also can be set for the whole fields accessibility, under 40 line use setAccessible AccessibleObject static methods, such as: AccessibleObject. SetAccessible (fromFields, true);

          I've shown you how to manipulate the methods and properties of a class using the Java reflection mechanism, and I'll show you how to create an object of a class at runtime with an example:


package com.wanggc.reflection;
 import java.lang.reflect.Field;
 
 public class ReflectionTest {
   public static void main(String[] args) throws Exception {
     //Create student objects
     Student student = new Student();
     //Assign a value to the student object
     student.setStuName("Wanggc");
     student.setStuAge();
     //Create a copy of the target object
     Student destStudent = (Student) copyBean(student);
     //Output copy result
     System.out.println(destStudent.getStuName() + ":"
         + destStudent.getStuAge());
   }
   
   private static Object copyBean(Object from) throws Exception {
     //Gets the Class object that copies the source object
     Class<?> fromClass = from.getClass();
     //Gets the property list of the copied source object
     Field[] fromFields = fromClass.getDeclaredFields();
     //Gets the Class object that copies the target object
     Object ints = fromClass.newInstance();
     for (Field fromField : fromFields) {
       //Sets the accessibility of the properties
       fromField.setAccessible(true);
       //Assigns the value of a property of the copy source object to the corresponding property of the copy target object
       fromField.set(ints, fromField.get(from));
     }
     return ints;
   }
 }
 
 class Student {
   
   private String stuName;
   
   private int stuAge;
   
   public String getStuName() {
     return stuName;
   }
   
   public void setStuName(String stuName) {
     this.stuName = stuName;
   }
   
   public int getStuAge() {
     return stuAge;
   }
   
   public void setStuAge(int stuAge) {
     this.stuAge = stuAge;
   }
}

          This example and the previous one run the same result. But the object returned by the copyBean method is no longer passed in from the outside, but is generated from within the method, as shown in line 40. Note: the Class newInstance method, can only create only contains the no-arg constructor Class, if only with a certain parameter constructor, then use a different way: fromClass. GetDeclaredConstructor (int. Class, String. The Class). NewInstance (24, "wanggc");

          At this point, the usual functions of Java reflection (methods that call objects at runtime, use of class attributes, objects that create class classes) are covered.

          Supplement: when you get the methods, properties, and constructors of a class, there are two corresponding methods: getXXX and getgetDeclaredXXX. The difference is that the former returns methods and properties that have access to public, including those in the parent class. But the latter returns methods and properties for all access rights, excluding those of the parent class.

The above is to introduce the Java launch mechanism, I hope you like.


Related articles: