preface
I often use the reflection mechanism in practical projects, so I will take some summary notes on the learned reflection usage for future replay.
There is such a class:
package com.example.demo; import com.alibaba.fastjson.annotation.JSONField; public class User { private String name; @Value( value ="age_a") private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
1, There are three ways to create a Class
1 - Class clazz = Class.forName("com.example.demo.User");
Note that the class name of forName("xxx") here needs to be a full name and an interface or class, otherwise it cannot be loaded.
2 - User user = new User();
Class clazz2 = user.getClass();
3 - Class clazz3 = User.class;
In the above three ways, you can get the Class object of Class User. Through Class, you can start playing reflection.
2, Reflection gets all properties and property types of the class
Class clazz = User.class; Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.println("Property name:"+field.getName()); System.out.println("Type of property:"+field.getGenericType().getTypeName()); }
Printout User properties and property types——
Attribute name: name
Type of attribute: Java lang.String
Attribute name: age
Type of attribute: Ava lang.String
After using reflection to obtain the field properties of the class, can reflection be used to create an object? The answer is yes.
For example, you can create an object by reflecting the field properties similar to the following code.
Map<String,Object> fileds = new HashMap<>(); fileds.put("name","Zhang San"); fileds.put("age","10"); Object o = User.class.newInstance(); Field[] fields = o.getClass().getDeclaredFields(); for (Field field : fields) { //After setting, private variables can be accessed by reflection field.setAccessible(true); //Assign values to attributes by reflection field.set(o,fileds.get(field.getName())); } User user1 = (User) o; System.out.println(user1.toString());
What scenarios might this be necessary? For example, the mapping of some internal data and external data fields can map the source data to the target data through a similar field reflection method, so as to obtain the target object that can be inserted into the database.
3, Reflection dynamically modifies the annotation value of class properties
Note that when setting the User class, we annotated one of the fields: @ value (value = "age_a"). This is a set value annotation. Since it is a set value, can it be dynamically modified according to different situations during code operation?
The annotations on the field are actually stored in a memberValues attribute, which is a map, which can be obtained in this way——
Field[] fields = User.class.getDeclaredFields(); for (Field field : fields) { //After setting, private variables can be accessed by reflection if ("age".equals(field.getName() )){ field.setAccessible(true); //Get the InvocationHandler held by the proxy instance of annotation InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class)); // Gets the memberValues field of InvocationHandler Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); memberValues.setAccessible(true); Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler); System.out.println(values); } }
debug break point, you can see——
This map < string, Object > stores all attribute values in the @ annotation. Here, @ value has only one value attribute——
public @interface Value { String value(); }
If you change it to something like @ JSONField(name = "age_a"), slightly modify the code above, such as:
Field[] fields = User.class.getDeclaredFields(); for (Field field : fields) { if ("age".equals(field.getName() )){ field.setAccessible(true); InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(JSONField.class)); ...... } }
@The internal properties of the JSONField annotation are as follows——
Running the code just now, you can see that all the attributes and corresponding attribute values in this annotation are obtained and stored in map < string, Object >.
At this point, let's go back to the previous question. What should we do to dynamically change the value of this annotation?
In fact, it is very simple. You only need to set the value directly, for example——
InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class)); Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); memberValues.setAccessible(true); Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler); values.put("value","new_age"); memberValues.setAccessible(false);
Just note that the key here needs to correspond to the attribute value in the annotation.
4, Method and calling method of reflection acquisition class
Object o=User.class.newInstance(); //Get the setAge method of the User through reflection, followed by string Class represents the parameter type of this setAge method. If there are multiple, they will be listed in order //Meanwhile, for other types, such as list and long, it is list class,Long. class Method m = (Method) o.getClass().getMethod("setAge",String.class); m.invoke(o,"name"); User user = (User) o; System.out.println(user);
It can be seen from the print that the age has been set to name, indicating that the setAge call was successful.
There are many such use scenarios in agents.
Finally, an encapsulation tool for converting Map into object is realized through reflection——
public Object MapToObject(Object object,Map<String, Object> map) throws IllegalAccessException { Class cla = object.getClass(); Field[] fields = cla.getDeclaredFields(); for(Field field:fields){ field.setAccessible(true); if("serialVersionUID".equals(field.getName()))continue; if(map.get(field.getName())!=null) { Object value=map.get(field.getName()); value=convertValType(value,field.getType()); field.set(object, value); } } return object; } private static Object convertValType(Object value, Class<?> fieldTypeClass) { Object o = null; if (Long.class.getName().equals(fieldTypeClass.getName()) || long.class.getName().equals(fieldTypeClass.getName())) { o = Long.parseLong(value.toString()); } else if (Integer.class.getName().equals(fieldTypeClass.getName()) || int.class.getName().equals(fieldTypeClass.getName())) { o = Integer.parseInt(value.toString()); } else if (Float.class.getName().equals(fieldTypeClass.getName()) || float.class.getName().equals(fieldTypeClass.getName())) { o = Float.parseFloat(value.toString()); } else if (Double.class.getName().equals(fieldTypeClass.getName()) || double.class.getName().equals(fieldTypeClass.getName())) { o = Double.parseDouble(value.toString()); } else { retVal = o; } return retVal; }