A comprehensive understanding of Java reflection mechanism

Keywords: Java Spring Attribute xml

Java's reflection mechanism is ubiquitous in practice. If you have worked for several years and have a little knowledge of Java's reflection mechanism, this article is definitely worth reading.

What is reflex

Reflection is one of the characteristics of Java. It allows running Java programs to obtain their own information and manipulate the internal properties of classes or objects.

Generally speaking, through the reflection mechanism, you can get the information of members and members of each type in the program or assembly at runtime.

Note that the point here is: runtime, not compile time. In general, the types of objects we write are determined at compile time. The Java reflection mechanism can dynamically create objects and call their properties, so the way to create objects is extremely flexible.

Although objects can be created dynamically by reflection, which increases flexibility, they are not available everywhere, but also consider performance, coding amount, security, object-oriented and so on.

We know that Java is object-oriented. If we use the reflection mechanism to manipulate the properties or methods in the object, the properties of object-oriented will be destroyed to some extent. At the same time, private variables can be modified by reflection mechanism, which also has some security problems.

But this does not affect the application of reflection in practice. Almost all major frameworks use Java reflection mechanism at least. Especially the mainstream Spring framework.

Function and purpose

Java reflection mainly provides the following functions:

  • Judge the class of any object at runtime;
  • Construct the object of any class at runtime;
  • Judge the member variables and methods of any class at runtime (even private methods can be called through reflection);
  • Calling a method of any object at run time

One of the most important uses of reflection is to develop a variety of generic frameworks. Take Spring for example. When configuring beans based on XML, we usually write the following code:

<bean class="com.choupangxia.UserServiceImpl">
</bean>

When Spring starts, it uses reflection mechanism to load the corresponding UserServiceImpl class and instantiate it. If the class does not exist, an exception will be thrown, and usually the stack information of the invoke method call will appear in the exception.

When Spring instantiates objects based on annotations, it also uses reflection mechanism. Here is a simple demo example to show how to get annotation information through reflection:

static void initUser(User user) throws IllegalAccessException {

	// Get all the properties in the User class (getFields cannot get the private property)
	Field[] fields = User.class.getDeclaredFields();

	// Traverse all properties
	for (Field field : fields) {
		// If there is this annotation on the attribute, the assignment is performed
		if (field.isAnnotationPresent(InitSex.class)) {
			InitSex init = field.getAnnotation(InitSex.class);
			field.setAccessible(true);
			// Set the gender value of the property
			field.set(user, init.sex().toString());
			System.out.println("Complete the modification of the attribute value. The modified value is:" + init.sex().toString());
		}
	}
}

The code is an example of the previous official account of Java, a comprehensive understanding of the "custom Annotation". The related articles can be concerned with the public number "new horizon of procedures" and reply to "annotations" to get the full text.

Let's not talk about more examples of Java reflection. It doesn't matter if we don't understand the above example. Let's introduce the specific use of Java reflection mechanism in detail.

Simple example

Let's take a look at the Java reflection mechanism through a simple example comparison. Let's start with an example of creating and using objects normally:

User user = new User();
user.setUsername("Official account: new horizon of procedure");
user.setAge(3);

So, what should we do to achieve uniform effect based on reflection mechanism? See the following implementation:

@Test
public void testCreateReflect() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
		InvocationTargetException, InstantiationException {
	// Get the Class object corresponding to User
	Class clz = Class.forName("com.choupangxia.reflect.User");
	// Get the parameterless constructor of User class
	Constructor constructor = clz.getConstructor();
	// Creating a User object through a constructor
	User user = (User) constructor.newInstance();
	user.setUsername("Official account: new horizon of procedure");
	user.setAge(3);
	System.out.println("username=" + user.getUsername());
	System.out.println("age=" + user.getAge());
}

In the above process, we get the Class object corresponding to User through Class.forName, get the constructor Constructor, create a User object through the constructor, and then call the corresponding method.

Of course, in the following steps, the User Class can also be completely eliminated, and the corresponding Method can be obtained directly through the Class object for calling. An example is as follows:

Method setUsernameMethod = clz.getMethod("setUsername", String.class);
Method setAgeMethod = clz.getMethod("setAge", int.class);

setUsernameMethod.invoke(obj,"Official account: new horizon of procedure");
setAgeMethod.invoke(obj,3);

This is also the case with the get method, so I will not repeat it.

After the above example, we have been able to create and use objects normally. Let's take a look at the common API of reflection, through which we can achieve more and more complex functions.

Reflection common API

Three methods of obtaining Class object

The first method: when you know the full pathname of the Class, you can use the Class.forName static method to get the Class object. The above example is obtained in this way:

Class clz = Class.forName("com.choupangxia.reflect.User");

The second way is through ". Class". The precondition is that you can get the corresponding class before compiling.

Class clz = User.class;

Third, use the getClass() method of the class object.

User user = new User();
Class clz = user.getClass();

Two ways to create objects

You can create an instance object of a Class through the newInstance() method of the Class object and the newInstance() method of the Constructor object.

The first is through the newInstance() method of the Class object.

Class clz = User.class;
User user = (User) clz.newInstance();

The second is through the newInstance() method of the Constructor object.

Class clz = Class.forName("com.choupangxia.reflect.User");
Constructor constructor = clz.getConstructor();
User user = (User) constructor.newInstance();

The second method is to create a Class object and select a specific construction method, while the Class object can only use the default parameterless construction method.

Class clz = User.class;
Constructor constructor = clz.getConstructor(String.class);
User user = (User) constructor.newInstance("Official account: new horizon of procedure");

Get class properties, methods, constructors

Get the non private property through the getFields() method of the Class object.

Field[] fields = clz.getFields();
for(Field field : fields){
	System.out.println(field.getName());
}

The User object properties in the above examples are all private and cannot be obtained directly through the above methods. You can change one of the properties to public to obtain it.

Get all properties through the getDeclaredFields() method of the Class object.

Field[] fields = clz.getDeclaredFields();
for(Field field : fields){
	System.out.println(field.getName());
}

Print results:

username
age

Of course, other values of the attribute can also be obtained. To modify the private attribute, you need to call the field.setAccessible(true) method first, and then assign a value. For specific applications, let's look back at the use of annotations in our first examples.

An example of the acquisition method is as follows:

Method[] methods = clz.getMethods();
for(Method method : methods){
	System.out.println(method.getName());
}

Print results:

setUsername
setAge
getUsername
getAge
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll

You can see that not only the methods of the current class are obtained, but also the methods defined in the Object class, the parent class of the class.

As mentioned above about the method of obtaining the constructor, we will not repeat it. The above methods have corresponding overloaded methods in Class, which can be used flexibly according to specific situations.

Creating arrays with reflection

Finally, let's look at an example of creating an array by reflection.

@Test
public void createArray() throws ClassNotFoundException {
	Class<?> cls = Class.forName("java.lang.String");
	Object array = Array.newInstance(cls,5);
	// Add content to array
	Array.set(array,0,"Hello");
	Array.set(array,1,"official account");
	Array.set(array,2,"New perspective of procedure");
	Array.set(array,3,"Two seniors");
	Array.set(array,4,"Java");
	// Gets the contents of the specified position in the array
	System.out.println(Array.get(array,2));
}

Summary

After the above learning, I think I have a further understanding of the Java reflection mechanism. At the beginning, we have said that the reflection mechanism is also inadequate. Therefore, if possible, try to use orthodox writing, but if you are developing a common framework, consider using it.

Later, we have the opportunity to explain the source of the reflection mechanism, and don't forget to pay attention to the official account: the new horizon of the program.

New vision of < center > < b > program

Posted by lifeson2112 on Wed, 25 Mar 2020 16:55:01 -0700