Ref
- Java Basics and Improved Dry goods series – Java reflection mechanism
- After reflection, I was admitted | the Denver nuggets
- Ref – Gets the value of an object property by reflection
- Ref – Takes attribute values on the generic class T using reflection
Basic
A program that analyzes class abilities is called reflection, and reflective mechanisms can be used
- Analyze the capabilities of the class at run time, obtaining the properties and methods of the class
- View objects at run time, for example, writing one
toString
Method is used by all classes - Implement common array operation code
- Call a Method with a Method object (this object is very similar to a function pointer in C++)
There are four main components of Java reflection
Class
Field
Constructor
Method
Here is a simple example of creating different objects based on class names. In the code, pass java.util.HashMap or java.util.linkedhashMap to create different Map objects.
public Map<Integer, Integer> getMap(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clazz = Class.forName(className);
return (Map<Integer, Integer>) clazz.newInstance();
}
public static void main(String[] args) throws Exception {
String className1 = "java.util.HashMap";
String className2 = "java.util.LinkedHashMap";
Map<Integer, Integer> map1 = getMap(className1); //HashMap
Map<Integer, Integer> map2 = getMap(className2); //LinkedHashMap
}
Copy the code
It is important to emphasize here that when you create an object using class.forname (), you pass in the full Class name path. For example, you need to pass in java.util.LinkedHashMap instead of LinkedHashMap, otherwise it will prompt you for the wrong class name, as shown below.
Exception in thread "main" java.lang.ClassNotFoundException: LinkedHashMap
Copy the code
Class Class and Class type
To understand reflection, first understand the Class Class, which is the foundation of reflection implementation.
In Java, each Class has its own Class object. When we write a.java file and use javac to compile it, a.class bytecode file is generated, which contains all the information about the Class, such as properties, constructors, methods
When the bytecode file is loaded into the virtual machine for execution, a Class object is generated in memory that contains all the information inside the Class and can be retrieved while the program is running.
Class is an instance object of the java.lang.Class Class, and Class is a Class named Class of all classes. This is how we create and represent ordinary objects
Code code1 = new Code();
Copy the code
All classes are Class objects
Class c = new Class();
Copy the code
But when we look at the source code for Class, we write it like this
/* * Private constructor. Only the Java Virtual Machine creates Class objects. * This constructor is not used and prevents the default constructor being * generated. */
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
Copy the code
As you can see, the constructor is private, and only the JVM can create Class objects, so you can’t just new a Class object like a normal Class. Although we cannot new a Class object, we can get one from an existing Class. There are three ways to get a Class object
The name of the class. The class
This method can be obtained only if the type of the class has been declared before compilationClass
object
Class clazz = SmallPineapple.class;
Copy the code
Instance. GetClass ()
: obtained by instantiating the objectClass
object
SmallPineapple sp = new SmallPineapple();
Class clazz = sp.getClass();
Copy the code
Class.forName(className)
Through:The fully qualified name of the classGets the class’sClass
object
Class clazz = Class.forName("com.bean.smallpineapple");
Copy the code
Each Class has only one Class object, which is the same as the Class object obtained using the above three methods.
A complete example is given below.
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
1 / / method
// Specify that any class has an implicit static member variable class, which is obtained by obtaining the class static member variable class
Class c1 = Code.class;
2 / / method
// Code1 is an object of Code obtained through the getClass() method of an object of a class
Class c2 = code1.getClass();
3 / / method
// The Class calls the forName method, obtained by the fully qualified name of a Class
Class c3 = Class.forName("com.trigl.reflect.Code"); System.out.println(c1.getName()); System.out.println(c2.getName()); System.out.println(c3.getName()); }}Copy the code
/ / the execution result com. Tengj. Reflect. ReflectDemo com. Tengj. Reflect. ReflectDemo com. Tengj. Reflect. ReflectDemoCopy the code
Here, c1, c2, and c3 are Class objects, which are exactly the same and have a scientific name called the Class type of Code.
As the name implies, a class type is a class type, which describes what a class is, what a class has, so we can know the properties and methods of a class from a class type, and we can call the properties and methods of a class, and that’s the basis of reflection, right
Now that we know how to get the Class, what can we do with this Class?
- Get member method
Method
- Get member variables
Field
- Get constructor
Constructor
The following is a detailed introduction.
Basic use of reflection
Let’s create a concrete entity class to show the basic use of reflection.
public class SmallPineapple {
public String name;
public int age;
private double weight; // Only you know your weight
public SmallPineapple(a) {}
public SmallPineapple(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void getInfo(a) {
System.out.print("["+ name + "The age is:" + age + "]"); }}Copy the code
Construct the instantiation object of the class
There are two ways to construct an instance of a class by reflection
Class
The objectnewInstance()
Method in which an object instance can only be created by calling the class’s default no-argument constructor.
Class clazz = Class.forName("com.bean.SmallPineapple"); SmallPineapple smallPineapple = (SmallPineapple) clazz.newInstance(); smallPineapple.getInfo(); // [null age is: 0]Copy the code
Constructor
Constructor callnewInstance()
methods
// The default constructor takes no arguments
Class clazz = Class.forName("com.bean.SmallPineapple");
Constructor constructor = clazz.getConstructor();
SmallPineapple smallPineapple2 = (SmallPineapple) constructor.newInstance("Little pineapple".21);
smallPineapple2.getInfo();
// [null age is: 0]
Copy the code
If clazz.getconstructor () is called without a parameter type, the default no-argument constructor is used to create an object instance.
// Specify the constructor
Class clazz = Class.forName("com.bean.SmallPineapple");
Constructor constructor = clazz.getConstructor(String.class, int.class);
SmallPineapple smallPineapple2 = (SmallPineapple) constructor.newInstance("Little pineapple".21);
smallPineapple2.getInfo();
// [The age of the pineapple is: 21]
Copy the code
clazz.getConstructor(Object… When paramTypes is called, specifying the type of argument to the constructor, the specified constructor is called, as shown in the code above.
Invoke – Invoke a method by reflection
Once an object of a Method class has been obtained by reflection, it can be executed by calling the Invoke Method.
invoke(Oject obj, Object... args)
Copy the code
In this method, parameter 1 specifies the object on which the method is called, and parameter 2 is the parameter list value of the method. If the method being called is static, you only need to pass null for parameter 1, because static methods are not associated with an object, only with a class.
In the following code, instantiate an object by reflection, then get the Method 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);
}
// [The age of the pineapple is: 21]
Copy the code
Gets the member Method -Method
// Get a single method of the class, not including the parent
public Method getDeclaredMethod(String name, Class
... parameterTypes)
// Get the public methods of the class, including the parent
public Method getMethod(String name, Class
... parameterTypes)
// Get all the methods of the class. The result is returned as an array
public Method[] getDeclaredMethods(a);
public Method[] getMethods();
Copy the code
The following is an example.
class Solution {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
try {
/ / generated Class
Class c1 = Class.forName("com.lbs0912.java.demo.entity.SmallPineapple");
// newInstance initializes an instance
Object o1 = c1.newInstance();
// Get method
Method method = c1.getMethod("getInfo", String.class, int.class);
// The method is invoked with invoke, the first parameter being the instance object followed by the concrete parameter value
method.invoke(o1, "lbs0912".28);
} catch(Exception e) { e.printStackTrace(); }}}Copy the code
The result is as follows
[AGE of LBS0912 is: 28]Copy the code
Sometimes we want to get information about all the member methods in a class, we can do the following.
Class c1 = Class.forName("com.lbs0912.java.demo.entity.SmallPineapple");
Method[] methods = c1.getDeclaredMethods();
for(Method method1:methods){
String methodName= method1.getName();
System.out.println(methodName);
}
Copy the code
Gets the member variable -field
The member variable of the class is also an object, which is an object of java.lang.Reflect. Field, so we get this information through methods encapsulated in java.lang.Reflect. Field.
Get a single member variable, using the following method of the Class Class
// Get all the variables declared by the class itself, excluding the variables of its parent class
public Field getDeclaredField(String name)
// Get all of the class's public member variables, including its parent
public Field getField(String name)
Copy the code
The following shows how to get the weight private member variable of an object.
try {
Class c1 = Class.forName("com.lbs0912.java.demo.entity.SmallPineapple");
Field field = c1.getDeclaredField("weight");
Object o = c1.newInstance();
// Set whether access is allowed. Since this variable is private, allow access manually
// If weight is public, this line is not needed
field.setAccessible(true);
Object weight = field.get(o);
System.out.println(weight);
} catch (Exception e) {
e.printStackTrace();
}
Copy the code
The execution result
0.0
Copy the code
Similarly, you can get information about all member variables, as shown below.
Field[] fields = c1.getDeclaredFields();
for(Field field1:fields){
System.out.println(field.getName() + "-" + field1.getType());
}
Copy the code
The execution result
weight---class java.lang.String
weight---int
weight---double
Copy the code
The above code is the property value obtained by using the field.get(object) method. There are two ways to get the value of an object property through reflection
field.get(object)
Through:get()
Method to get the value of an attributemethod.invoke(object)
Through:invoke()
Method to get the value of an attribute
Refer to the link
- Ref – Gets the value of an object property by reflection
- Ref – Takes attribute values on the generic class T using reflection
Two entity classes are presented here for subsequent code demonstrations.
@Data
public class User {
private Duty duty;
}
@Data
public class Duty {
private String name;
}
Copy the code
Get the property value with the get() method
/** * Get the value of the field * from the object or its parent class by the field name@paramObject Object instance *@paramFieldName fieldName *@returnThe value corresponding to the field */
private static Object getValue(Object object,String fieldName){
if(null == object || StringUtils.isBlank(fieldName)){
return null;
}
Field field = null; Class<? > clazz = object.getClass();for(; clazz ! = Object.class; clazz = clazz.getSuperclass()){// Find the parent class until the parent class is Object
try{
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
} catch (Exception e){
log.error("getValue exception",e); }}return null;
}
Copy the code
public static void main(String[] args) {
Duty duty = new Duty("testName");
String nameStr = (String) getValue(duty,"name");
System.out.println(getValue(duty,"name")); //testName
System.out.println(nameStr); //testName
}
Copy the code
Get the property value via the method.invoke() method
In the following code, get the name of the corresponding method using the PropertyDescriptor.
/** * Get the value of the field from the object or its parent by the field name (call the dictionary's get method) *@paramObject Object instance *@paramFieldName fieldName *@returnThe value corresponding to the field */
public static Object getValueOfGet(Object object, String fieldName){
if (object == null || StringUtils.isBlank(fieldName)) {
return null;
}
Field field = null; Class<? > clazz = object.getClass();for(; clazz ! = Object.class; clazz = clazz.getSuperclass()) {try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
// Get the get method
Method getMethod = pd.getReadMethod();
The get method returns an Object
return getMethod.invoke(object);
// where the statement is equivalent to
// Method method = clazz.getMethod("getName");
// return method.invoke(object);
} catch (Exception e) {
log.error("getValue exception",e); }}return null;
}
Copy the code
public static void main(String[] args) {
Duty duty = new Duty("testName");
System.out.println(getValueOfGet(duty,"name"));
}
Copy the code
If you do not use PropertyDescriptor, you can simply use the get + property name to get the method name.
private static Method getReadMethod(String name, Class
clazz) {
String methodName = "get" + ProString.upperFirst(name);
try {
return clazz.getDeclaredMethod(methodName);
} catch (NoSuchMethodException | SecurityException e) {
return null; }}Copy the code
Get constructor
The Constructor of a class is an object, it is a Java. Lang. Reflect. The Constructor of an object, so we through the Java. Lang. Reflect. Encapsulated inside the Constructor method to get the information.
Get a single constructor, implemented through the following methods of the Class Class
// Get all constructors for the class, excluding the parent class's constructors
public Constructor<T> getDeclaredConstructor(Class
... parameterTypes)
// Get all the public constructors for the class, including the parent class
public Constructor<T> getConstructor(Class
... parameterTypes)
Copy the code
An example is shown below.
try {
Class c1 = Class.forName("com.lbs0912.java.demo.entity.SmallPineapple");
Constructor constructor = c1.getConstructor(String.class,int.class);
// Set whether access is allowed. Since the constructor is private, allow access manually
// This line is not needed if the constructor is public
constructor.setAccessible(true);
Object o1 = constructor.newInstance("lbs0912".28);
} catch (Exception e) {
e.printStackTrace();
}
Copy the code
Reflection application scenarios
Common application scenarios of reflection include
- Spring instantiation object: When the program starts, Spring reads the configuration file
applicationContext.xml
And instantiate all the tags inside into the IOC container. - Reflection + Factory pattern: Eliminate multiple branches in the factory by reflection. If you need to produce new classes, you don’t need to worry about the factory class. The factory class can handle all kinds of new classes.
- JDBC Connection to a database: When JDBC is used to connect to a database, the reflection load driver class is used to specify the driver class for connecting to the database
Spring’s IOC container
In Spring, you will often write a context configuration file, applicationContext.xml, which contains bean configuration. When the program starts, it reads the.xml file, parses out all the
tags, and instantiates objects into the IOC container.
<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>
Copy the code
After the above documents is defined through the ClassPathXmlApplicationContext loading the configuration file, the program starts, the Spring will all the bean is instantiated in the configuration file, in the IOC container, the IOC container is essentially a factory, The factory passes in the ID attribute of the
tag to get the corresponding instance.
public class Main {
public static void main(String[] args) {
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
SmallPineapple smallPineapple = (SmallPineapple) ac.getBean("smallpineapple");
smallPineapple.getInfo(); // [The age of the pineapple is: 21]}}Copy the code
Spring’s instantiation process is simplified to reflect the steps of instantiating an object
- To obtain
Class
Object constructor - Called through the constructor
newInstance()
Instantiate an object
Of course, Spring does a lot of extra work when instantiating objects to make current development easy and stable.
Reflection trap point
advantages
- Increased program flexibility: Flexibility to instantiate different objects in the face of changing requirements
disadvantages
- Breaks class encapsulation: access can be forced
private
Embellished information - Performance loss: Reflection requires far more checking and parsing steps than directly instantiating objects, calling methods, and accessing variables that the JVM cannot optimize for.
Break the encapsulation of classes
In reflection, a call to setAccessable(true) forces external access to information about a private modifier, regardless of access modifier restrictions.
The following is illustrated with specific codes.
public class SmallPineapple {
public String name;
public int age;
private double weight; // Only you know your weight
public SmallPineapple(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight; }}Copy the code
The weight attribute of the SmallPineapple object is private. In reflection, setAccessable(true) is called to make the property accessible from the outside world.
SmallPineapple sp = new SmallPineapple("Little pineapple".21."54.5");
Clazz clazz = Class.forName(sp.getClass());
Field weight = clazz.getDeclaredField("weight");
weight.setAccessable(true);
System.out.println("The weight of the pineapple is:" + weight.get(sp));
// The small pineapple weighs 54.5 kg
Copy the code