[learning notes] reflection operations commonly used in Java

1, Introduction to reflection

1.1 prior knowledge

class is also an object

In the object-oriented world, * * the Class in java (the Class we define) is also an instance object, * * is an instance object of Class class, which is called (class type) on the official website.

Class loading information

1.2 what is reflection?

In the running state of the program:

  • For any class, you can know all the properties and methods of this class;
  • For any object, you can call any of its methods and properties;

This kind of dynamically obtained information and the function of dynamically calling the method of the object are called the reflection mechanism of java language.

1.3 what can reflection do?

The reflection mechanism mainly provides the following functions:

  1. Judge the class of any object at run time;
  2. Judge the member variables and methods of any class at run time;
  3. Construct the object of any class at runtime;
  4. Call the method of any object at run time;
  5. Generate dynamic proxy

[note]: it is obtained at runtime, not at compile time.

For example: many times when we write code with compilers such as ide or eclipse, when we enter a point (such as student.) The compiler will automatically list its properties and methods, and reflection will be used here.

2, Common reflection operations

The implementation of java reflection mechanism depends on four classes: Class, Constructor, Field and Method. The commonly used operations basically focus on these four classes.

The following shows some common operations in the form of requirement demo. We need to make some preparations before the show.

2.1 preparation

Construct a Student class to test:

package reflectDemo;

public class Student {
	//3 private attributes
    private String name;
    private Integer age;
    private String sex;
	
	//Two construction methods: no parameter + with parameter
    public Student(){}
    public Student(String name ,Integer age, String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

	//2 public functions: no parameter + with parameter
    public String getNameWithAge(){
        return this.name +"What is your age" + this.age + "year.";
    }
    public String getNameWithKeyInfo(String keyInfo){
        return this.name +"My motto is" + keyInfo + ".";
    }
    
	//1 private function with parameters
    private String getAllInfo(String keyInfo){
        return  this.name + "Age is " + this.getAge() 
        +", Gender is " + this.getSex() + ", The motto is:" + keyInfo;
    }

	// Other tool functions
    public String getName(){
        return this.name;
    }
    public String getSex(){
        return this.sex;
    }
    public Integer getAge(){
        return  this.age;
    }
    @Override
    public String toString(){
        return  this.name + "Age is " + this.getAge() 
        +", Gender is " + this.getSex();
    }
}

2.2 get class object

Class objects are the most commonly used in reflection. There are three main ways to obtain class objects

  • According to class name: class name class
  • By object: object getClass()
  • According to the fully qualified class name: class Forname (fully qualified class name)

The demo is as follows:

public class ReflectStudent {

	Student bigBear = new Student("BigBear", 29,"male");

    public static void main(String[] args){
        //1. Get class information through fully qualified class name
        Class<?> class1 = Class.forName("reflectDemo.Student");
        System.out.println("1,adopt[Fully qualified class name]Get class information:" + class1.getName());
        
        //2. Get class information through object
        Class<?> class2 = bigBear.getClass();
        System.out.println("2,adopt[object]Get class information:" + class2.getName());
        
        //3. Get class information by class name
        Class<?> class3 = Student.class;
        System.out.println("3,adopt[Class name]Get class information" + class3.getName());
	}
}

Output result:

1,adopt[Fully qualified class name]Get class information: reflectDemo.Student

2,adopt[object]Get class information: reflectDemo.Student

3,adopt[Class name]Get class information reflectDemo.Student

What is the class object used for? There are many things you can do. You can get the Constructor, Method, attribute Field, creation object, etc. here are some examples.

2.3 obtaining construction method (Constructor)

Next, get the class object of the student through the "object. getClass()", then get the corresponding construction method without parameters and with parameters through the class object, and use the construction method to obtain the student object instance.

public class ReflectStudent {

	Student bigBear = new Student("BigBear", 29,"male");

    public static void main(String[] args){
         //case1: get parameterless construction method
        Constructor<?> constructor1 = bigBear.getClass().getConstructor();
        // Creating objects using parameterless construction
        Student studentByConstructor1 = (Student)constructor1.newInstance();
        System.out.println("studentByConstructor1 = " + studentByConstructor1.toString());
        
        //case2: get constructor with parameters
        Constructor<?> constructor2 = bigBear.getClass().getConstructor(String.class, Integer.class, String.class);
        //Creating objects using the parametric construction method
        Student studentByConstructor2 = (Student)constructor2.newInstance("Tie Zhu Wang", 17 , "female");
        System.out.println("studentByConstructor2 = " + studentByConstructor2.toString());
	}
}

Corresponding output results:

studentByConstructor1 = null Age is null, Gender is null

studentByConstructor2 = Wang Tiezhu is 17 years old, Gender is female

2.4 acquisition method

Methods in a class can be classified into public and non-public types according to access restrictions; According to the classification of inheritance relationship, it can be divided into its own and inherited from the parent class. When using reflection acquisition method, these four cases can be summarized into two cases:

case1: use:

//Gets a single specified method
Method method = clazz.getMethod(String name, Class<?>... parameterTypes);

//Get all methods
Method[] methods = clazz.getMethods()

You can obtain the methods with access permission in the class (only public methods, including the inherited methods in the parent class)

case2: use

//Gets a single specified method
Method method = clazz.getDeclaredMethod(String name, Class<?>... parameterTypes)

//Get all methods
Method[] methods = clazz.getDeclaredMethods()

You can get all the methods in the class (public methods + non-public methods, excluding the inherited methods in the parent class)

Corresponding demo:

public class ReflectStudent {

	Student bigBear = new Student("BigBear", 29,"male");

    public static void main(String[] args){
       // case1: call parameterless public method: getNameWithAge()
        Method method = Student.class.getMethod("getNameWithAge");
        System.out.println("method_Reflection test_Get no parameters through [class name] public method: " + (String)method.invoke(bigBear));
        Method method01 = bigBear.getClass().getMethod("getNameWithAge");
        System.out.println("method_Reflection test_Get no parameters through [object] public method: " + method01.invoke(bigBear));
        
        // case2: call public method with parameters: getNameWithKeyInfo(String keyInfo)
        Method method1 = Student.class.getMethod("getNameWithKeyInfo", String.class);
        String result2 = (String)method1.invoke(bigBear,"Be a down-to-earth man, Work hard");
        System.out.println("Reflection test_Call with parameters public method: " + result2);
		
		
		//case3: call private method with parameters:
		try {
            //case3.1 use getMethod 
            Class<?> classForPrivate = bigBear.getClass();
            Method methodForPrivate = classForPrivate.getMethod("getAllInfo", String.class);
            String resultForPrivate1 = (String)methodForPrivate.invoke(bigBear, "Be a down-to-earth man, Work hard");
            System.out.println("resultForPrivate1 = " + resultForPrivate);
        }catch (Exception e){
            System.out.println("resultForPrivate1 error! " + e);
        }
        try {
        	 //case3.2 use getDeclaredMethod 
             Class<?> classForPrivate2 = bigBear.getClass();
             Method methodForPrivate2 = classForPrivate2.getDeclaredMethod("getAllInfo", String.class);
             String resultForPrivate2 = (String)methodForPrivate2.invoke(bigBear, "Be a down-to-earth man, Work hard ");
             System.out.println("resultForPrivate2 = " + resultForPrivate2);
         }catch (Exception e){
             System.out.println("resultForPrivate2 error! " + e);
         }
         //case3.3 use getDeclaredMethod + setAccessible to set
         Class<?> classForPrivate3 = bigBear.getClass();
         Method methodForPrivate3 = classForPrivate3.getDeclaredMethod("getAllInfo", String.class);
         methodForPrivate3.setAccessible(true);
         String resultForPrivate3 = (String)methodForPrivate3.invoke(bigBear, "Be a down-to-earth man, Work hard ");
         System.out.println("resultForPrivate3 = " + resultForPrivate3);
	}
}

Corresponding output results:

// Result of case1
method_Reflection test_Get no parameters through [class name] public method: BigBear My age is 29.
method_Reflection test_Get no parameters through [object] public method: BigBear My age is 29.

// Result of case 2
 Reflection test_Call with parameters public method: BigBear My motto is: be a down-to-earth man, Work hard.

// Result of case 3
// case3. Results of 1
resultForPrivate1 error! java.lang.NoSuchMethodException: reflectDemo.Student.getAllInfo(java.lang.String)
// case3.2 Results
resultForPrivate2 error! java.lang.IllegalAccessException: Class reflectDemo.ReflectStudent can not access a member of class reflectDemo.Student with modifiers "private"
// case3. Results of 3
resultForPrivate3 = BigBear The age is 29, Gender is male, The motto is: be a down-to-earth man, Work hard: 

In case3:

  • Use calzz Get the private method by getmethod (name) and report Java Lang. nosuchmethodexception exception;
  • Calzz. Is used Getdeclaredmethod (name) method to obtain the private method. When invoking the private method, it will report Java Lang. illegalaccessexception exception;
  • Only use calzz Getdeclaredmethod (name) method is used to obtain the private method, and method Setaccessible (true) cancel the access check to access private objects.

For the "private method access" scenario, when writing a single test, you can directly test the specified private method logic, which is more convenient.

2.5 get attribute (file)

Attribute fields in a class can be classified into public and non-public types according to access restrictions; According to the classification of inheritance relationship, it can be divided into its own and inherited from the parent class. When using reflection acquisition method, these four cases can be summarized into two cases:

case1:

//Gets a single specified property
Field field = clazz.getField(String name);

//Get all properties
Field[] fields = clazz.getField();	

Gets the property field of the specified name (only the public field, including the inherited properties in the parent class).

case2:

//Gets a single specified property
Field field = clazz.getDeclaredField(String name)

//Get all properties
Field[] fields = clazz.getDeclaredFields();	

You can get all attribute fields in the class (public + non-public fields, excluding the attribute fields inherited from the parent class)

In Student, our attributes are all of private type, so here we use getDeclaredField method to get the attributes of and assign values to them. Corresponding demo:

public class ReflectStudent {

	Student bigBear = new Student("BigBear", 29,"male");

    public static void main(String[] args){
    	//Assign a value to the happyBird object attribute by reflection
       Student happyBird = new Student();
       Field nameField = happyBird.getClass().getDeclaredField("name");
       nameField.setAccessible(true);
       nameField.set(happyBird, "HappyBird");
       
       Field ageField =  happyBird.getClass().getDeclaredField("age");
       ageField.setAccessible(true);
       ageField.set(happyBird, 28);
       
       Field sexField =   Student.class.getDeclaredField("sex");
       sexField.setAccessible(true);
       sexField.set(happyBird, "female");
       
       System.out.println("The result of assigning values to all fields by reflection:" + happyBird.toString() );
	}
}

The output is:

After assigning a value to all fields, the result is reflected: HappyBird The age is 28, Gender is female

When we get an object without a set method, we need to assign values to its related attributes, which can be done in the above way.

2.6 creating objects by reflection

There are two methods: one is to create through the Constructor mentioned above, and the other is to create through the class object. Let's take a look at the demo:

public class ReflectStudent {

	Student bigBear = new Student("BigBear", 29,"male");

    public static void main(String[] args){
    	// case1: created by Class object, only parameterless constructor can be used
       Class<?> studentClass = bigBear.getClass();
       Student studentByClassNewInstance = (Student)studentClass.newInstance();
       System.out.println("studentByClassNewInstance = " + studentByClassNewInstance.toString());
       
       // case2: it can be created through the Constructor. You can use parameterless or parameterless constructors
       Constructor<?> studentConstructorWithoutPar = bigBear.getClass().getConstructor();
       Student studentByConstructorWithoutPar = (Student)studentConstructorWithoutPar.newInstance();
       System.out.println("studentByConstructorWithNoPra = " + studentByConstructorWithoutPar.toString());
       
       Constructor<?> studentConstructorWithPar = bigBear.getClass()
           .getConstructor(String.class, Integer.class, String.class);
       Student studentByConstructorWithPar = (Student)studentConstructorWithPar.newInstance("Emerald flower", 17 , "male");
       System.out.println("studentByConstructorWithPra = " + studentByConstructorWithPar.toString());
	}
}

Corresponding results:

//case1
studentByClassNewInstance = null Age is null, Gender is null
//case2
studentByConstructorWithNoPra = null Age is null, Gender is null
studentByConstructorWithPra = The age of Cuihua is 17, Gender is male

Here are two questions to explore:
Q1. When initializing a class and generating an instance, what is the difference between new and newInstance()?
A1: the difference is that objects are created in different ways. The former uses the class loading mechanism.
In addition, from the perspective of scalable, extensible, reusable and other software ideas:

  • newInstance: weak type, inefficient, and can only call parameterless construction; However, it is the inevitable choice of technical methods such as IOC, reflection, face-to-face interface programming and dependency inversion;
  • Call: public, relatively efficient, any type; However, it can only realize the instantiation of specific classes, which is not suitable for interface programming.

Reference documents

ref1. Java foundation - detailed explanation of reflection mechanism

Keywords: Java reflection

Added by mkoga on Thu, 24 Feb 2022 17:58:23 +0200