When we learn the basic use of reflection, I will use a SmallPineapple class as a template. First, let's get familiar with the basic composition of this class: properties, constructors and methods
public class SmallPineapple { public String name; public int age; private double weight; // Only you know your weight public SmallPineapple() {} public SmallPineapple(String name, int age) { this.name = name; this.age = age; } public void getInfo() { System.out.print("["+ name + " Your age is:" + age + "]"); } }
There are many uses in reflection. The common functions are as follows:
- Get the Class object of a Class at run time
- Construct an instantiated object of a class at run time
- Get all the information of a class at run time: variables, methods, constructors and annotations
Gets the Class object of the Class
In java, each class will have its own class object when we finish writing java file, compiled with javac, will produce a bytecode file Class. The bytecode file contains all the information of the class, such as attributes, construction methods and methods. When the bytecode file is loaded into the virtual machine for execution, a class object will be generated in memory. It contains all the information inside the class and can be obtained when the program is running.
There are three methods to obtain Class objects:
- Class name Class: in this way, class objects can be obtained only if the type of the class has been declared before compilation
Class clazz = SmallPineapple.class;
- example. getClass(): get the Class object of the instance by instantiating the object
SmallPineapple sp = new SmallPineapple(); Class clazz = sp.getClass();
- Class.forName(className): get the class object of the class through the fully qualified name of the class
Class clazz = Class.forName("com.bean.smallpineapple");
When you get the Class object, you can do whatever you want: peel it (get Class information), command it to do things (call its methods), and see through everything (get properties). In short, it has no privacy.
However, in the program, there is only one Class object for each Class, that is, you have only one slave. We use the above three methods to test, and print all Class objects in the three methods are the same.
Class clazz1 = Class.forName("com.bean.SmallPineapple"); Class clazz2 = SmallPineapple.class; SmallPineapple instance = new SmallPineapple(); Class clazz3 = instance.getClass(); System.out.println("Class.forName() == SmallPineapple.class:" + (clazz1 == clazz2)); System.out.println("Class.forName() == instance.getClass():" + (clazz1 == clazz3)); System.out.println("instance.getClass() == SmallPineapple.class:" + (clazz2 == clazz3));
The reason why there is only one Class object in memory involves the two parent delegation model of JVM Class loading mechanism, which ensures that only one Class object will be generated in memory for each Class when the program runs. I'm not going to expand the description here. It can be simply understood that the JVM helps us ensure that at most one Class object exists in memory.
Instantiation object of construction class
There are two ways to construct an instance of a class through reflection:
- Class object calls newInstance() method
Class clazz = Class.forName("com.bean.SmallPineapple"); SmallPineapple smallPineapple = (SmallPineapple) clazz.newInstance(); smallPineapple.getInfo(); // [null age is: 0]
Even if SmallPineapple has explicitly defined the construction method, all attribute values in the instance created through newInstance() are the initial values of the corresponding type, because the default parameterless constructor will be called by the newInstance() construction instance.
- The Constructor constructor calls the newInstance() method
Class clazz = Class.forName("com.bean.SmallPineapple"); Constructor constructor = clazz.getConstructor(String.class, int.class); constructor.setAccessible(true); SmallPineapple smallPineapple2 = (SmallPineapple) constructor.newInstance("Little pineapple", 21); smallPineapple2.getInfo(); // [age of little pineapple: 21]
Specify to obtain the Constructor of the specified parameter type through the getConstructor(Object... paramTypes) method. When the Constructor calls newInstance(Object... paramValues), the value of the Constructor parameter is passed in. Similarly, an instance can be constructed, and the internal attribute has been assigned.
Calling newInstance() through Class object will take the default no reference method. If you want to construct an instance by explicit construction method, you need to call getConstructor() method from Class to get the corresponding constructor and instantiate the object by constructor.
These API s are most commonly encountered in development. Of course, there are many overloaded methods. Due to the length of this article, and if each method is explained one by one, we can't remember it, so it's enough to look in the class when used.
Get all the information of a class
Class object contains all the information of this class. The information we can see during compilation is the variables, methods and constructors of this class. It is also the information most often obtained at runtime.
Get the variable in the class (Field)
- Field[] getFields(): get all variables modified by public in the class
- Field getField(String name): get a variable in the class according to the variable name, which must be modified by public
- Field [] getdeclaraedfields(): get all variables in the class, but cannot get inherited variables
- Field getDeclaredField(String name): get a variable in the class according to the name. Inherited variables cannot be obtained
Get Method in class
-
Method[] getMethods(): get all methods modified by public in the class
-
Method getMethod(String name, Class... <? > paramtypes): get the corresponding method according to the name and parameter type. The method must be modified by public
-
Method [] getdeclaraedmethods(): get all methods, but cannot get inherited methods
-
Method getDeclaredMethod(String name, Class... <? > paramtypes): get the corresponding method according to the name and parameter type. Inherited methods cannot be obtained
Gets the Constructor of the class
- Constructor [] getconstructors(): get all constructors modified by public in the class
- Constructor getConstructor(Class... <? > paramtypes): get a constructor in the class according to the parameter type, which must be modified by public
- Constructor [] getdeclaraedconstructors(): get all constructors in the class
- Constructor getdeclaraedconstructor (class... <? > paramtypes): obtain the corresponding constructor according to the parameter type
Each function is divided into 2 categories by Declared:
Methods decorated with Declared: you can get all variables, methods and constructors contained in the class, but you can't get inherited information
Methods without Declared modification: you can obtain the variables, methods and constructors of public modification in this class and obtain the inherited information
If you want to obtain * * all (including inheritance) * * variables, methods and constructors in the class, you need to call getXXXs() and getdeclaredxxs() at the same time, and use the Set set to store the variables, constructors and methods they obtain, so as to prevent the two methods from obtaining the same thing.
For example, to get all the variables in the SmallPineapple class, the code should be written as follows.
Class clazz = Class.forName("com.bean.SmallPineapple"); // Get public properties, including inheritance Field[] fields1 = clazz.getFields(); // Gets all properties, excluding inheritance Field[] fields2 = clazz.getDeclaredFields(); // Summarize all attributes to set Set<Field> allFields = new HashSet<>(); allFields.addAll(Arrays.asList(fields1)); allFields.addAll(Arrays.asList(fields2));
I don't know if you have found an interesting thing. If the attribute of the parent class is modified with protected, it can't be obtained by reflection.
Scope of protected modifier: only access under the same package or subclass is allowed, and can be inherited to subclasses.
getFields() can only get the variable value of the public attribute of this class;
Getdeclaraedfields() can only get all the attributes of this class, excluding inherited ones; In any case, we can't get the variable modified by the protected attribute of the parent class, but its does exist in the child class.
Get annotation
Obtaining annotations is screwed out separately, because it is not a kind of information specific to Class objects. Each variable, Method and Constructor can be modified by annotations. Therefore, in reflection, Field, Constructor and Method Class objects can call the following methods to obtain annotations marked on them.
- Annotation[] getAnnotations(): get all annotations on the object
- Annotation getAnnotation(Class annotaionClass): pass in the annotation type to get a specific annotation on the object
- Annotation [] getdeclaraedannotations(): get all annotations of explicit annotations on the object, but cannot get inherited annotations
- Annotation getdeclaraedannotation (class annotationclass): obtain a specific annotation on the object according to the annotation type. Inherited annotations cannot be obtained
The annotation can only be obtained through reflection when the @ retention of the annotation is marked as RUNTIME. There are three saving strategies for @ retention:
- SOURCE: only saved in * * SOURCE file (. java) * *, that is, the annotation will only be retained in the SOURCE file. The compiler will ignore the annotation during compilation, such as @ Override annotation
- CLASS: saved in the bytecode file (. class). The annotation will follow the bytecode file with compilation, but the annotation will not be parsed at run time
- RUNTIME: it is the most frequently used saving strategy to save until RUNTIME. All information of the annotation can be obtained at RUNTIME
As in the following example, the SmallPineapple class inherits the abstract class Pineapple. The getInfo() method is marked with the @ Override annotation, and the subclass is marked with the @ Transient annotation. All annotations on the subclass Override method are obtained at runtime, and only the @ Transient information can be obtained.
public abstract class Pineapple { public abstract void getInfo(); } public class SmallPineapple extends Pineapple { @Transient @Override public void getInfo() { System.out.print("What is the height and age of little pineapple:" + height + "cm ; " + age + "year"); } }
Start the class Bootstrap to obtain the annotation information on the getInfo() method in the SmallPineapple class:
public class Bootstrap { /** * Determine the specific class object according to the full class name path passed in at run time * @param path The full class name path of the class */ public static void execute(String path) throws Exception { Class obj = Class.forName(path); Method method = obj.getMethod("getInfo"); Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation.toString()); } } public static void main(String[] args) throws Exception { execute("com.pineapple.SmallPineapple"); } } // @java.beans.Transient(value=true)
Calling methods through reflection
After a Method class object is obtained through reflection, it can be executed by calling the invoke Method.
- Invoke (object obj, object... Args): parameter ` ` 1 'specifies the * * object * * calling the method, and parameter ` 2' is the parameter list value of the method.
If the called method is a static method, parameter 1 only needs to pass in null, because the static method is not related to an object, but only to a class.
You can instantiate an object through reflection, obtain the Method object, and call invoke() to specify the getInfo() Method of SmallPineapple.
Class clazz = Class.forName("com.bean.SmallPineapple"); Constructor constructor = clazz.getConstructor(String.class, int.class); constructor.setAccessible(true); SmallPineapple sp = (SmallPineapple) constructor.newInstance("Little pineapple", 21); Method method = clazz.getMethod("getInfo"); if (method != null) { method.invoke(sp, null); } // [age of little pineapple: 21]
Application scenario of reflection
Here are three common application scenarios of reflection:
- Spring instantiation object: when the program starts, spring will read the configuration file ApplicationContext XML and parse all the tags in it and instantiate them into the IOC container.
- Reflection + factory mode: eliminate multiple branches in the factory through reflection. If you need to produce new classes, you don't need to pay attention to factory classes. Factory classes can deal with all kinds of new classes. Reflection can make the program more robust.
- JDBC connection to database: when using JDBC to connect to the database, the reflection loading driver class is used when specifying the driver class to connect to the database
IOC container for Spring
In Spring, we often write a context configuration file ApplicationContext xml, which is about bean configuration. When the program starts, it will read the xml file, parse all < bean > tags, and instantiate objects into the IOC container.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="smallpineapple" class="com.bean.SmallPineapple"> <constructor-arg type="java.lang.String" value="Little pineapple"/> <constructor-arg type="int" value="21"/> </bean> </beans>
After defining the above file, load the configuration file through ClassPathXmlApplicationContext. When the program starts, Spring will instantiate all bean s in the configuration file and put them into the IOC container. The IOC container is essentially a factory. The corresponding instance is obtained through the id attribute of the factory passed in \ label.
public class Main { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); SmallPineapple smallPineapple = (SmallPineapple) ac.getBean("smallpineapple"); smallPineapple.getInfo(); // [age of little pineapple: 21] } }
After simplifying the process of instantiating objects, Spring can be understood as reflecting the steps of instantiating objects:
- Gets the constructor of the Class object
- Instantiate the object by calling newInstance() through the constructor
Of course, Spring does a lot of extra operations when instantiating objects, so that the current development can be convenient and stable.
In the following articles, an article will be specially written to explain how to use reflection to implement a simple version of IOC container. The principle of IOC container is very simple. As long as you master the idea of reflection and understand the common API s of reflection, I can provide a simple idea: use HashMap to store all instances, key represents the id of \ tag, and value stores the corresponding instances, This corresponds to that the objects managed by the Spring IOC container are singleton by default.
Reflection + abstract factory pattern
In the traditional factory mode, if you need to produce new subclasses, you need to modify the factory class and add new branches in the factory class;
public class MapFactory { public Map<Object, object> produceMap(String name) { if ("HashMap".equals(name)) { return new HashMap<>(); } else if ("TreeMap".equals(name)) { return new TreeMap<>(); } // ยทยทยท } }
Using the combination of reflection and factory mode, when generating a new subclass, the factory class does not need to modify anything and can focus on the implementation of the subclass. When the subclass is determined, the factory can produce the subclass.
The core idea of reflection + abstract factory is:
- At runtime, the fully qualified names of different subclasses are passed in through parameters to obtain different Class objects, and the newInstance() method is called to return different subclasses. Careful readers will find that the concept of subclass is mentioned, so the reflection + abstract factory pattern is generally used for inheritance or interface implementation.
For example, we can only determine which Map structure to use at runtime. We can use reflection to pass in the fully qualified name of a specific Map to instantiate a specific subclass.
public class MapFactory { /** * @param className Fully qualified name of class */ public Map<Object, Object> produceMap(String className) { Class clazz = Class.forName(className); Map<Object, Object> map = clazz.newInstance(); return map; } }
className can be specified as Java util. HashMap, or Java util. Treemap and so on, depending on the business scenario.
JDBC loading database driver classes
When importing a third-party library, the JVM will not take the initiative to load the externally imported classes, but wait until it is actually used to load the required classes. That's why we can pass in the fully qualified name of the driver class when obtaining the database connection and give it to the JVM to load the class.
# *** Learning technology must formulate a clear learning route, so as to learn efficiently. There is no need to do ineffective work, which is a waste of time and no efficiency. You might as well learn according to my route. ![](https://img-blog.csdnimg.cn/img_convert/d7a6ddd2bb9494ee1ad0132fc5304223.png) ![](https://img-blog.csdnimg.cn/img_convert/d7ac2d43ad4eedc63eb8a175760eecfa.png) ![](https://img-blog.csdnimg.cn/img_convert/b3e04893684082264f7e0c971badb6c0.png) # Final interview sharing You may as well brush more questions directly on Niuke and Likou. At the same time, I also took some interview questions to share with you, which is also obtained from some big guys. You may as well brush more questions to make a wave for gold, nine silver and ten! ![](https://img-blog.csdnimg.cn/img_convert/c930dfb3da75997e8471963def2c237a.png) ![](https://img-blog.csdnimg.cn/img_convert/5d43e26670daa67c989c4b71ff817688.png) A clear learning route, so that we can learn efficiently. There is no need to do ineffective work, which is a waste of time and no efficiency. You might as well follow my route to learn. [External chain picture transfer...(img-wfLDHijg-1628621606864)] [External chain picture transfer...(img-ZTO6Lwgq-1628621606867)] [External chain picture transfer...(img-QcrKTbQq-1628621606868)] # Final interview sharing You may as well brush more questions directly on Niuke and Likou. At the same time, I also took some interview questions to share with you, which is also obtained from some big guys. You may as well brush more questions to make a wave for gold, nine silver and ten! [External chain picture transfer...(img-5Vmx1MZI-1628621606870)] [External chain picture transfer...(img-bPPymtaJ-1628621606871)] **Finally, complete if necessary pdf Version, you can like this article[Click here for free](https://gitee.com/vip204888/java-p7)**