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:
- Judge the class of any object at run time;
- Judge the member variables and methods of any class at run time;
- Construct the object of any class at runtime;
- Call the method of any object at run time;
- 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