JAVA learning record - Reflect

(ps: This article is applicable to super cute new, so it will say some basic things. Don't spray if you don't like it)

catalogue

Why is it called reflection?  

There are three common methods for Java reflection foundation code:

Let's take an example:

Output:

What's the use of reflection?

Examples of optimizing code through reflection:

Operation results:

All common methods of reflection

be careful

practice

answer

Why is it called reflection?  

reflect can map variables, methods, etc. in an object into variable objects, method objects, etc. An inappropriate analogy is as like as two peas in a mirror, because the reflection of light causes a mirror image that is exactly the same as that of Object, and the image in the mirror is the object we can manipulate. Object Because we operate the object in the mirror, not the object that originally existed in the mirror, we can let any object look in the mirror, but the way we operate the object in the mirror can remain the same.

There are three common methods for Java reflection foundation code:

// 1. There are two methods to obtain the Class of an object:
        Class<?> c = Object.class;
        Class<?> c = new Object().getClass();

// 2. Get the Method of an object [need to throw exception NoSuchMethodException]:
        Object.getMethod(String: Method name, Class<?>[]: Method parameter list);

// 3.invoke the Method of an object
// [exception invocationtargetexception and illegalaccessexception need to be thrown]:
        Method.invoke(Object: object, Object[]: Parameter value);

Let's take an example:

[ Student.java ]

public class Student {
    private String name;
    private Integer age;

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Careful students can find that the age field is Integer instead of int, because the reflection operation is a class object (Integer is the encapsulated class of int). If you use int type, some strange errors will occur, but it is not that you can't use int, but beginners don't recommend it.

[ Reflect.java ]

import java.lang.reflect.Method;

public class Reflect {
    public static void main(String[] args) {
        Student s = new Student("Zha Zha Hui", 21);

        System.out.println(s.toString());

        try {
            Class<?> c = s.getClass();
            Method m = c.getMethod("setAge", Integer.class);
            m.invoke(s, 16);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(s.toString());
    }
}

Output:

Student{name='Zha Zha Hui', age=21}
Student{name='Zha Zha Hui', age=16}

You can see that the setAge method in Student class has been successfully called.

What's the use of reflection?

Many students will be curious that reflection is so troublesome. Why don't I call the method of the original object directly?

Reflection can optimize a large number of if else statements in the code, making the code more elegant. The most important thing of reflection is that it can be loaded dynamically. At present, almost all popular frameworks on the market (such as Spring and Mybatis) need reflection to complete. Reflection can also realize various operations, which need to be explored by yourself.

Examples of optimizing code through reflection:

[ Action.java ]

public class Actions {

    public void login(String username, String password){ // Sign in
        System.out.printf("Sign in: username: %s, password: %s\n", username, password);
    }

    public void regist(String username, String password){  // register
        System.out.printf("register: username: %s, password: %s\n", username, password);
    }
}

[ Reflect.java ]

import java.lang.reflect.Method;

public class Reflect {

    public static void Login(String action, String username, String password){
        try{
            Method c = Actions.class.getMethod(action, String.class, String.class);
            c.invoke(new Actions(), username, password);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

[ Login.java ]

public class Login {
    public static void main(String[] args) {
        Reflect.Login("login", "account", "123");
        Reflect.Login("regist", "test", "testPass");
    }
}

Operation results:

Sign in: username: account, password: 123
 register: username: test, password: testPass

As can be seen from the above, the amount of code of the main class (Login.java) is greatly reduced, and the operation of login or registration can be realized in one line. Moreover, in the actual development project, we can update it without modifying the source code of the main class, just in action Just update the code in Java. For example, you need to add a function to log off an account, just in action Add public void logoff (String account, String password) {} in Java.

The reflection operation in this example can avoid code bloating and make the code better maintained. However, the disadvantage is that reflection is slower than if else statements. This disadvantage can be ignored in small projects.

All common methods of reflection

// Get Class
        Class<?> cl = Object.class;  // Gets the bytecode file object of the object
        Class<?> cl2 = Basic data type.class;  //  Type includes basic data type and reference data type
        Class<?> cl3 = Class.forName(String: Bytecode full path);  // Get a bytecode file through a string. The string must be a full pathname

// Operations related to Constructor
        Object obj = cl.newInstance();  // Parameterless construction object, equivalent to new Object [deprecated]
        Object obj2 = cl.getDeclaredConstructor().newInstance();  // Same as above [JAVA 1.9 +]

        Constructor con = cl.getDeclaredConstructor(class<?>[]: Parameter type);  // Parametric structure
        Object obj3 = con.newInstance(Object[]: Parameter content);  // Parametric construction instantiation object

        Constructor[] cons = cl.getConstrutors();  // Get all constructors
        con.getName();  // Gets the name of the constructor
        con.getParameterCount();  // Gets the number of parameters of the construction method
        con.getParameterTypes();  // Gets the parameter type of the constructor

// Operations related to Field
        Field field = cl.getField(String: Attribute name);  // Get public property
        Field field2 = cl.getDeclaredField(String: Attribute name);  // Get any attribute
        Field[] fieldPublic = cl.getFields();  // Get all public properties
        Field[] fields = cl.getDeclaredFields();  // Get all properties
        String name = field.getName(); // Get property name 
		Class fieldClass = field.getType() Gets the bytecode file for the attribute type
        field.setAccessible(Boolean: Mandatory);  // When it is true, you can force operations such as modifying the property
        field.set(Object: object, Object: value);  // Set the value of the object's field, which is equivalent to object fieldName = value;
        Object obj4 = field.get();  // Gets the value of the property

// Method related operations
        Method m = cl.getMethod(String: Method name, Class<?>[]: Method parameter list);  // Get public method, getmethod (string methodname, class <? >... Classes)
        Method m2 = cl.getDeclaredMethod(String: Method name, Class<?>[]: Method parameter list);  // Get any method

be careful

In most cases, getDeclaredXXX and getXXX are common, but only getDeclaredXXX can be used when the access modifier of a property or method is protected.

practice

Try to write a reflection tool class, ReflectUtils, to get or set the value of the property in a class containing Getter and Setter methods, and you can call any method in a class.

answer

[ ReflectUtils ]

import java.lang.reflect.Method;

public class ReflectUtils {
    
    // Reflection call GET
    public static Object invokeGetter(Object obj, String fieldName){
        System.out.println(joinString("get", fieldName));
        return invokeMethod(obj, joinString("get", fieldName), null, null);
    }

    // Reflection call SET
    public static void invokeSetter(Object obj, String fieldName, Object value){
        invokeMethod(obj, joinString("set", fieldName), new Class<?>[]{value.getClass()}, new Object[]{value});
    }

    /**
     * Call the method of the object
     * @param obj object
     * @param methodName Method name
     * @param parameterTypes parameter list
     * @param args parameter
     * @return Return value of the called method
     */
    public static Object invokeMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object[] args){
        try {
            Class<?> c = obj.getClass();
            Method me = c.getDeclaredMethod(methodName, parameterTypes);
            return me.invoke(obj, args);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * Get a standard getter or setter method name
     * @param prefix Prefix, get / set
     * @param fieldName Attribute name
     * @return Prefix + uppercase attribute name
     */
    public static String joinString(String prefix, String fieldName){
        char[] chars = fieldName.toCharArray();
        chars[0] = chars[0] >= 97 ? (char) (chars[0] - 32) : chars[0];  // a is 97
        return prefix + String.valueOf(chars);
    }
}

Keywords: Java Back-end

Added by jibosh on Sun, 16 Jan 2022 23:27:42 +0200