Summary of reflection usage in JAVA programming

Java reflection is a very powerful mechanism. It can detect the fields, methods and constructors of internal classes in the same system. Reflection technology is widely used in many Java frameworks, such as Hibernate and Spring. It can be said that the characteristics of reflection mechanism enable java to build extremely powerful and flexible systems.

Although the Java reflection mechanism has the disadvantages of low efficiency, slow speed and low security, in many scenarios, these characteristics are not the main factors, or the execution efficiency can be gradually improved through caching or JVM optimization.

According to website https://docs.oracle.com/javase/tutorial/reflect/index.html Reflection technology can check or modify the behavior of applications in the JVM at run time, which is a relatively high-level language feature and a powerful technology. Reflection can enable applications to achieve operations that are impossible.

The following describes and summarizes the basic knowledge of Java reflection:

First, define a MyBase class, which has both private and public fields. There are also public and private methods. An example of MyBase class is as follows:

package com.hwdev.demo;
/**
 * Base class example
 * @author wangming
 */
public class MyBase {
    //Public field
    public int version  = 1;
    //Private field
    private String date = "2021-05-18" ;
    //Public method
    public void say2(String msg){
    System.out.println("Hello " + msg);
    }
    //Private method
    private String getData(){
        return this.date;
    }
}

Here we define another Hello class, which inherits from MyBase class. Through inheritance, it is mainly used to verify the reflection usage of reflection for parent and child classes.

package com.hwdev.demo;
/**
 *
 * @author wangming
 */
public class Hello extends MyBase {

    public String author = "JackWang" ;
    public int version  = 1;
    private String company = "kzcloud" ;

    public void say(String msg){
         System.out.println("Hello " + msg);
    }
    public void setAuthor(String author){
        this.author = author;
    }
    public String getAuthor(){
        return this.author;
    }
    private int getVersion(){
        return this.version;
    }
}

With regard to Java reflection, the powerful function is to dynamically invoke the method from the system or modify the field values of one object through the string configuration, and Class. The forname method can obtain the corresponding class object by passing in the full path string name of the class, which is very convenient. In addition, through getField method and GetMethod method, you can obtain the specified fields and methods and call them dynamically.

package com.hwdev.demo;
import java.lang.reflect.*;
import java.util.Arrays;
/**
 * The first use of reflection is class forName
 * @author wangming
 */
public class ReflectDemo01 {

     public static void Test() {
        try
        {
            //Find Class by string full path Class name
            Class helloC = Class.forName("com.hwdev.demo.Hello"); 
            //Get all public field arrays, and private ones cannot be obtained
            Field [] fields = helloC.getFields();
            //Print field array contents
            System.out.println(Arrays.toString(fields));
            //[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version]
            //instantiation 
            Object obj = helloC.newInstance();
            //Getting specific fields is more efficient than traversing Field []
            Field f = helloC.getField("author");
            if (f != null){
                //Close safety inspection to improve efficiency
                f.setAccessible(true);
                //Get field author content
                String author = (String)f.get(obj);
                System.out.println("author=" + author);
                //author=JackWang
            }
            //Get all public method arrays, and private methods cannot be obtained
            Method [] methods = helloC.getMethods();
            //Print methods, array contents, subclasses and other methods can also be obtained
            System.out.println(Arrays.toString(methods));
            //All methods in this class
            Method [] methods2 = helloC.getDeclaredMethods();
            //Print method array contents
            System.out.println(Arrays.toString(methods2));
            //Get the specific method. The second parameter is string Class is the parameter type of the say method
            //say(java.lang.String)
            Method m = helloC.getDeclaredMethod("say",String.class); 
            if (m != null){
                //Close safety inspection to improve efficiency
                m.setAccessible(true);
                //Get field author content
                Object returnValue = m.invoke(obj, new Object[]{"Java"});
                //Hello Java
                if (returnValue!=null){
                    System.out.println("returnValue =" + returnValue);    
                }
            }

        }catch(ClassNotFoundException | SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }    
}

Note here: XXX By default, getmethods () method will return the public methods of this class, parent class and parent interface, while XXX Getdeclaraedmethods () returns all methods of this class, including private methods. Similarly, the usage of other getXXX and getDeclaredXXX in the reflection API is similar.

package com.hwdev;
import com.hwdev.demo.ReflectDemo01;
/**
 * 
 * @author wangming
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //The first use of reflection is class forName
        ReflectDemo01.Test();
    }    
}

Execute the program, and the output results are as follows:

[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version, public int com.hwdev.demo.MyBase.version]
author=JackWang
[public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), public void com.hwdev.demo.MyBase.say2(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()]
[public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), private int com.hwdev.demo.Hello.getVersion()]

From the output result, field [] fields = helloc getFields(); You can get not only the public field of the Hello class, but also the public field of the parent class MyBase: com hwdev. demo. MyBase. version

And method [] Methods2 = helloc getDeclaredMethods(); You can get all the methods of this class, that is, the Hello class, including public and private methods. Therefore, Java reflection can access private fields and methods of classes to expose internal information, which is also the reason for the security problems of Java reflection.

Because Java methods support overloading, there can be multiple methods with the same name, i.e. different parameters. Therefore, when calling methods with reflection, you need to specify the parameter type of the method, so that you can specify which method signature to call, such as method m = helloc getDeclaredMethod("say",String.class); The call is public void com hwdev. demo. Hello. say(java.lang.String) .

In addition to using class In addition to forname for reflection, you can also obtain the reflected object in the following ways:

Hello hello = new Hello();
Class helloC = hello.getClass();
Field [] fields = helloC.getFields();
//
Class helloC = Hello.class; 
Field [] fields = helloC.getFields();
     Here's how to use it Java Examples of modifying private fields and calling private methods by reflection:

package com.hwdev.demo;
import java.lang.reflect.*;
/**
 * Reflection access private fields and methods
 * @author wangming
 */
public class ReflectDemo02 {

     public static void Test() {
        try
        {
            //Find Class by existing Class
            Class helloC = Hello.class; 
            //instantiation 
            Object obj = helloC.newInstance();
            //Get specific private fields
            Field f = helloC.getDeclaredField("company");
            if (f != null){
                //Private must be turned on
                f.setAccessible(true);
                //Set private field value
                f.set(obj, "newKZ");
                //Get field author content
                String fv = (String)f.get(obj);
                System.out.println("company=" + fv);
                //company=newKZ
            } 
            //Get private method
            Method m = helloC.getDeclaredMethod("getVersion", null); 
            if (m != null){
                //Private must be turned on
                m.setAccessible(true);
                Object returnValue = m.invoke(obj, null);
                if (returnValue!=null){
                    //returnValue =1
                    System.out.println("returnValue =" + returnValue);    
                }
            }

        }catch(SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }    
}

In addition, Java reflection can obtain annotation information, which is very useful for ORM framework.

package com.hwdev.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Annotation example
 * @author wangming
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ORMAnnotation {
    public String FieldName();
    public String FieldType();
}
Among them,@Retention(RetentionPolicy.RUNTIME)Indicates that annotations can be accessed through reflection at run time.@Target(ElementType.FIELD) Indicates that this annotation can only be used on fields. Similarly, you can FIELD Change to Type perhaps Method Wait.

package com.hwdev.demo;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
/**
 * Reflection or field annotation
 * @author wangming
 */
public class ReflectDemo03 {

     public static void Test() {
        try
        {

            Class helloC = Class.forName("com.hwdev.demo.HelloAnnotation");      
            Field[] fields = helloC.getDeclaredFields();
            for(Field f : fields){
                 //Close safety inspection to improve efficiency
                f.setAccessible(true);
                Annotation ann = f.getAnnotation(ORMAnnotation.class);
                if(ann instanceof ORMAnnotation){
                    ORMAnnotation ormAnn = (ORMAnnotation) ann;
                    System.out.println("FieldName=" + ormAnn.FieldName());
                    System.out.println("FieldType=" + ormAnn.FieldType());
                }

            }          

        }catch(ClassNotFoundException | SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }    
}
   When this example is executed, the output is as follows:
FieldName=f_author
FieldType=varchar(50)
FieldName=f_ver
FieldType=int

Again, let's introduce how to use reflection to obtain the number and type of method parameters, including generic information acquisition:

package com.hwdev.demo;

import java.util.ArrayList;
import java.util.List;

/**
 * Generic example
 * @author wangming
 */
public class GenericCls {
   protected List<String> myList = new ArrayList(); 
   public GenericCls(int size){      
       for(int i = 0;i<size;i++){
           myList.add("item"+i);
       }
   }
   public  List<String> getList(){ 
      return this.myList;
   }
   public String getList(int idx){ 
      return this.myList.get(idx);
   }
}
package com.hwdev.demo;
import java.lang.reflect.*;
/**
 * Reflection acquisition method parameters
 * @author wangming
 */
public class ReflectDemo05 {

     public static void Test() {
        try
        {

            Class helloC = Class.forName("com.hwdev.demo.GenericCls"); 
            //constructor call 
            Object obj = helloC.getConstructor(int.class).newInstance(3);
            Method method = helloC.getMethod("getList", int.class);
            Class<?> returnType = method.getReturnType();
            System.out.println("ReturnType = " + returnType.getName());
            Parameter[] params = method.getParameters();
            for(Parameter p : params){    
                System.out.println("ParameterizedType = " + p.getParameterizedType());
                System.out.println("getModifiers = " + p.getModifiers());
                System.out.println("getName = " + p.getName());
                System.out.println("getType = " + p.getType());
            }
           //Call method
           Object ret =  method.invoke(obj, new Object[]{2});
           System.out.println("ret = " + ret.toString());
            Method method2 = helloC.getMethod("getList", null);
            Type greturnType = method2.getGenericReturnType();
            System.out.println("getGenericReturnType = " + returnType.getName());
            if(greturnType instanceof ParameterizedType){
                ParameterizedType type = (ParameterizedType) greturnType;
                System.out.println("type = " + type.getTypeName());
                Type[] typeArguments = type.getActualTypeArguments();
                for(Type typeArgument : typeArguments){
                    Class typeArgClass = (Class) typeArgument;
                    System.out.println("typeArgClass = " + typeArgClass);
                }
            }
        }catch(ClassNotFoundException | SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }    
}

Execute the above example, and the output is as follows.

ReturnType = java.lang.String
ParameterizedType = int
getModifiers = 0
getName = arg0
getType = int
ret = item2
getGenericReturnType = java.lang.String
type = java.util.List<java.lang.String>
typeArgClass = class java.lang.String

There are many knowledge points about reflection, such as using reflection technology to realize the dynamic loading of plug-ins. The efficiency of reflection can be solved by using an efficient third-party reflection library or adding a buffer mechanism, which will not be repeated here.

Added by frans-jan on Thu, 03 Feb 2022 00:41:23 +0200