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