Reflection in Java Basics 21
“This is the 21st day of my participation in the Gwen Challenge in November. See details of the event: The Last Gwen Challenge 2021”.
About the author
- The authors introduce
🍓 blog home page: author’s home page 🍓 Introduction: JAVA quality creator 🥇, a junior student 🎓, participated in various provincial and national competitions during school, and won a series of honors
Reflection mechanism
If the reflection mechanism is only for ordinary developers, it is not significant. It is generally used as the architecture design of some systems, including the open source framework to learn later, so it is almost the reflection mechanism.
Know the reflection
Reflection refers to the reverse processing of an object. First observe the following “positive” operations. By default, a package must be imported in order to produce an instantiated object of the class.
The so-called “anti” obtains the source information of the Object according to the Object. The original source of the operation of “anti” is a method of Object.
- Get class object :public final
getClass() returns an object of the Class that describes the Class.
package com.day16.demo;
import java.util.Date;
import javafx.scene.chart.PieChart.Data;
public class FanShedemo {
public static void main(String[] args) {
Date date = new Date();
//java.util.DateSystem.out.println(date.getClass().getName()); }}Copy the code
At this point, through the source of the object, it is the essence of anti. Behind the reflection is no longer an object, but the source behind the object.
The object returned by this getClass() method is a Class object, so this Class is the source of all reflection operations, but there is one more thing that needs to be explained before we get into the actual use of this method. Since Class is the source of all reflection operations, this Class is definitely the most important. To get an instantiated object of this class, Java defines three methods:
Method 1: Use the getClass() method of the Object class
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) {
Date de = new Date();// Do the same thingClass<? > cla =de.getClass();// Get the class object
System.out.println(cla.getName());/ / to}}Copy the code
Method 2: Through “class”. The Class”
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) {
Date de = new Date();// Do the same thingClass<? > cla =Date.class;// Get the class object
System.out.println(cla.getName());/ / to}}Copy the code
Method 3: Use a static method defined inside the Class
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) throws Exception{
Date de = new Date();// Do the same thingClass<? > cla =Class.forName("java.util.Date");// Get the class object
System.out.println(cla.getName());/ / to}}Copy the code
There is a magic to the three methods given above, except that the first form produces Date instantiation objects, while the second and third do not
Instantiate the fetch object. One of the most immediate benefits of getting a Class object is that it can be instantiated directly by reflection. In Class there is a method:
- Instantiate objects through reflection: public T newInstance() throws InstantiationException IllegalAccessException
Reflection instantiates objects
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) throws Exception{ Class<? > cla =Class.forName("java.util.Date");// Get the class object
Object o = cla.newInstance();// Get the Date objectSystem.out.println(o); }}Copy the code
Now you can see that there is a reflection mechanism operation in addition to the new keyword for the instantiation of the object, and this operation is a bit more complicated than the previous new operation, but what is the use?
The development mode of the program has always been strong: reduce coupling as much as possible, and the best way to reduce coupling is to use the interface, but even if you use the interface can not escape the keyword new, mostly because in fact new is the key culprit of coupling.
Gets parent information
Reflection can perform all of the operations an Object can perform, and most importantly, all of these operations can be performed based on the Object type.
In Java, any program Class must actually have a parent Class. You can use this method to obtain the parent Class or implementation of the parent interface. There are two methods:
Public package getPackage() | Gets the package name of the class |
---|---|
Public class <? super T> getSuperclass() | Gets the Class object of the parent Class |
Public class <? >[] getInterfaces() | Get parent interface |
Gets information about the class
package com.day16.demo;
import java.util.Arrays;
interface IFruit{}
interface IMessage{}
class Person implements IFruit.IMessage{}public class FanShedemo {
public static void main(String[] args) throws Exception{ Class<? > cls = Person.class; System.out.println(cls.getPackage().getName()); System.out.println(cls.getSuperclass().getName()); Class<? > itf[] = cls.getInterfaces(); System.out.println(Arrays.toString(itf)); }}Copy the code
All the key information on the class structure can be obtained through our reflection.
Reflection call construction
A Class can have more than one constructor, and if we want to get calls constructed in the Class, we can use the two methods provided by the Class Class
Public Constructor getConstructor(class <? >… parameterTypes) throws NoSuchMethodException, SecurityException |
Gets the constructor of the specified argument type |
---|---|
public Constructor<? >[] getConstructors() throws SecurityException |
Gets all constructs in the class |
The return type of the two methods mentioned above are Java lang. Reflect. The Constructor class instantiation objects, the class focuses on a method, instantiation objects: public T newInstance (Object… initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
Get information for all constructors in the class – Complete information for the Constructor is obtained using the toString() method of the Constructor class
package com.day16.demo;
import java.lang.reflect.Constructor;
import java.util.Arrays;
class Person {
public Person(a){}
public Person(String name){}
public Person(String name , int age){}}public class FanShedemo {
public static void main(String[] args) throws Exception{ Class<? > cls = Person.class; Constructor<? > cst [] = cls.getConstructors();for (int i = 0; i < cst.length; i++) { System.out.println(cst[i]); }}}Copy the code
Using the getName() method is more cumbersome
Piecing together constructor operations yourself
package com.day16.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Arrays;
class Person {
public Person(a) throws Exception,RuntimeException{}
public Person (String name) throws Exception,RuntimeException{}
public Person(String name , int age) throws Exception,RuntimeException{}}public class FanShedemo {
public static void main(String[] args) throws Exception{ Class<? > cls = Person.class; Constructor<? > cst [] = cls.getConstructors();for (int i = 0; i < cst.length; i++) {
System.out.print(Modifier.toString(cst[i].getModifiers()) + "");
System.out.print(cst[i].getName() + "("); Class <? > params [] = cst[i].getParameterTypes();for (int j = 0; j < params.length; j++) {
System.out.print(params[j].getName());
if(j < params.length - 1){
System.out.print(",");
}
}
System.out.print(")"); Class<? > exps [] = cst[i].getExceptionTypes();if(exps.length > 0){
System.out.print(" throws ");
for (int j = 0; j < exps.length; j++) {
System.out.print(exps[j].getName());
if(j < exps.length - 1){
System.out.print(","); } } } System.out.println(); }}}Copy the code
The purpose of learning the Constructor class is not to analyze the composition of methods, but rather to focus on the conclusion of the problem: when defining a simple Java class, a no-argument construct must be preserved.
Observe that there is no method of no-parameter construction
package com.day16.demo;
import java.lang.reflect.Constructor;
class Per{
private String name;
private int age;
public Per(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString(a) {
return "Per [name=" + name + ", age=" + age + "]"; }}public class FanShedemo {
public static void main(String[] args) throws Exception{ Class<? > cls = Per.class;// Get the class objectObject obj=cls.newInstance(); }}Copy the code
Exception in thread "main" java.lang.InstantiationException: com.day16.demo.Person
at java.lang.Class.newInstance(Class.java:427)
at com.day16.demo.FanShedemo.main(FanShedemo.java:19)
Caused by: java.lang.NoSuchMethodException: com.day16.demo.Person.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)...1 more
Copy the code
Run at this time when the error message “Java. Lang. InstancetiationException” because of the way more than use reflection to instantiate objects need is class provides a no-parameter constructor, but now since no has a constructor, then find a constructor must be clear.
Instantiate objects through the Constructor class
package com.day16.demo;
import java.lang.reflect.Constructor;
class Per{
private String name;
private int age;
public Per(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString(a) {
return "Per [name=" + name + ", age=" + age + "]"; }}public class FanShedemo2 {
public static void main(String[] args) throws Exception{ Class<? > cls = Per.class;// Get the class object
// Now explicitly says get the constructor object of the specified argument typeConstructor<? > cont = cls.getConstructor(String.class,int.class);
System.out.println(cont.newInstance("Zhang".19)); }}Copy the code
That’s all you need to know about a line of simple Java classes that write no-argument constructs.
Reflection call method
When you get an instantiated object from a Class, the next thing you need to call is the Class method, so you can continue to use the Class Class to get a method definition defined in a Class:
public Method[] getMethods() throws SecurityException |
Get all methods |
---|---|
public Method getMethod(String name,Class<? >… parameterTypes) throws NoSuchMethodException, SecurityException |
Get the specified method |
It turns out that all of the above methods return objects of the Java.lang. Method class.
Gets all methods defined in a class
package com.day16.demo;
import java.lang.reflect.Method;
class Student{
private String name;
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name; }}public class FanShedemo3 {
public static void main(String[] args) throws Exception { Class<? > cls = Class.forName("com.day16.demo.Student");
Method met [] = cls.getMethods();
for (int i = 0; i < met.length; i++) { System.out.println(met[i]); }}}Copy the code
The most useful thing about getting a Method object is not the Method listing (which is used in development tools), but the most useful thing about getting a Method object is that you can use reflection to call the Method: public Object invoke(Object obj,Object… Args) throws IllegalAccessException IllegalArgumentException, InvocationTargetException before call in the class method used is “object. Method “, but now with reflection, you can call the action methods of specified subclasses directly from the Object class. Explain why setter and getter methods are so strictly named.
Use reflection to call the setName(),getName() methods in the Student class.
package com.day16.demo;
import java.lang.reflect.Method;
class Student{
private String name;
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name; }}public class FanShedemo3 {
public static void main(String[] args) throws Exception { Class<? > cls = Class.forName("com.day16.demo.Student");
Object obj = cls.newInstance();// instantiate the object
Method met [] = cls.getMethods();
Method setM=cls.getMethod("setName",String.class);// Build methods with reflection
Method getM=cls.getMethod("getName");
setM.invoke(obj, "Xiao Zhang");// Pass parameters as key-value pairs. This process is equivalent to setMObject result = getM.invoke(obj); System.out.println(result); }}Copy the code
This is how simple Java classes will be used in all future technology development, most of which will have to follow standards.
Reflection call member
To get a member of a class, you can use the following methods: Public Field[] getDeclaredFields() throws SecurityException Obtains the specified member: public Field getDeclaredField(String name)throws NoSuchFieldException, SecurityException
Gets all members of this class
package com.day16.demo;
import java.lang.reflect.Field;
class Person4{
private String name;
}
public class FanShedemo4 {
public static void main(String[] args) throws Exception{ Class<? > cls = Class.forName("com.day16.demo.Person4");
Object obj = cls.newInstance();
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
//private java.lang.String com.day16.demo.Person4.nameSystem.out.println(fields[i]); }}}Copy the code
But finding Field actually leads to an interesting operation that provides two methods in the Field class:
Set the property content (similar to: object. Property =) : public void set (Object obj, Object value) throws IllegalArgumentException, IllegalAccessException obtain attribute content (similar to: Object. Properties: public Object get (Object obj) throws IllegalArgumentException, IllegalAccessException
However, in terms of class development requirements, it has always been emphasized that the attributes in the class must be wrapped, so now before calling to find a way to unwrap.
- Unencapsulate: public void setAccessible(Boolean Flag)throws SecurityException
Use reflection to manipulate properties in a class
package com.day16.demo;
import java.lang.reflect.Field;
class Person4{
private String name;
}
public class FanShedemo4 {
public static void main(String[] args) throws Exception{ Class<? > cls = Class.forName("com.day16.demo.Person4");
Object obj = cls.newInstance();
Field field = cls.getDeclaredField("name");// Get the Person4 member variable
// Since the attribute set by Person4 is private, it cannot be operated on
field.setAccessible(true);/// resolve encapsulation
field.set(obj, "Zhang"); System.out.println(field.get(obj)); }}Copy the code
Although reflection operates directly on properties in a class, there is no program that operates directly on properties, it operates through setter, getter methods.
Reflection and Simple Java Classes – Single-level VO operating principles
If you now have a simple Java class, the properties in that simple Java class must be set using the setter as originally done, and the getter will continue to be used if you get it.
Emp.java
package com.day16.vo;
public class Emp {
private String ename;
private String job;
public String getEname(a) {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob(a) {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString(a) {
return "Emp [ename=" + ename + ", job=" + job + "]"; }}Copy the code
EmpAction.java
package com.day16.action;
import com.day16.vo.Emp;
public class EmpAction {
private Emp emp = new Emp();
public void setValue(String val ){// Set the property content
this.emp.setEname("SMI");
this.emp.setJob("STRACK");
}
public Emp getEmp(a){
returnemp; }}Copy the code
EmpDemo.java
package com.day16.demo;
import com.day16.action.EmpAction;
public class EmpDemo {
public static void main(String[] args) {
String value="emp.ename:smi|emp.job:strack";
EmpAction action = newEmpAction(); action.setValue(value); System.out.println(action.getEmp()); }}Copy the code
Unipolar automatic VO setting implementation
All operations are now performed by the TestDemo class calling the EmpAciton class, whose main purpose is to locate the type of property to manipulate. At the same time, the program should conform to all the simple Java class development forms, which means that our design must be implemented in a separate class.
Since Bean processing must repeat the object information, we also need to prepare two program classes: StringUtils, which will handle string operations (after all, the first letter of the property needs to be capitalized), and then write the specific operations of an object (get object, set object content).
Tools – BeanOperation. Java
package com.day16.util;
/ * * *@authorThis class is mainly responsible for the implementation of automatic VO matching processing operation, itself does not need to be completed by instantiating objects, so the constructor is private */
public class BeanOperation {
private BeanOperation(a){}
/ * * *@paramActionObject represents the current object * of the program class that currently issues the setting request@paramMSG all the properties of the specific content and format "attribute name: | attribute names: content" * * /
public static void setBeanValue(Object actionObject,String msg) throws Exception{
String result [] = msg.split("\ \ |");
for (int i = 0; i < result.length; i++) {
// A split is required for the given attribute name and content
String temp[] = result[i].split(":");
String attribute = temp[0];// Property names, including "XxxAction property and properties of concrete simple AJava classes"
String value = temp[1];// Receive specific content attributes
String fields [] = attribute.split("\ \.");
Object currentObject = ObjectUtils.getObject(actionObject,fields[0]);
ObjectUtils.setObjectValue(currentObject, fields[1], value); }}}Copy the code
Tools – StringUtils. Java
package com.day16.util;
/ * * *@authorShengrui Zhang * For the string processing operation */
public class StringUtils {
private StringUtils(a){}
/ * * *@param str
* @returnReturns uppercase * uppercase */
public static String initcap(String str){
return str.substring(0.1).toUpperCase() + str.substring(1); }}Copy the code
Tools – ObjectUtils. Java
package com.day16.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/ * * *@authorThe main function of this class is to call the getter and setter methods */ in the response class according to the property name
public class ObjectUtils {
private ObjectUtils(a){}
/** * Sets the class attribute * based on the specified class object@paramInstantiation object * of the class of the wrapo attribute@paramAttribute Attribute name *@paramValue Property content */
public static void setObjectValue(Object wrapo,String attribute, String value) throws Exception{
// Call the Field object with the specified property, and get the object type. If there is no property, the operation cannot continue
Field field = wrapo.getClass().getDeclaredField(attribute);// Check whether the attribute exists
if(field == null){
field = wrapo.getClass().getField(attribute);
}
if(field == null) {// Do not get the corresponding member variable
return ;// This attribute must not exist
}
String methodName = "set" + StringUtils.initcap(attribute);
Method method = wrapo.getClass().getMethod(methodName,field.getType());
method.invoke(wrapo, value);
}
/** * is responsible for calling the getter method * of the specified class@paramWrapo represents the object * from which the method is to be called@paramAttribute Indicates the attribute name *@returnThe result of calling the object */
public static Object getObject(Object wrapo,String attribute) throws Exception{
String methodName = "get" + StringUtils.initcap(attribute);// Define getter methods
// Call the Field object with the specified property, and get the object type. If there is no property, the operation cannot continue
Field field = wrapo.getClass().getDeclaredField(attribute);
if(field == null){
field = wrapo.getClass().getField(attribute);
}
if(field == null) {// Do not get the corresponding member variable
return null;// This attribute must not exist
}
Method method = wrapo.getClass().getMethod(methodName);
returnmethod.invoke(wrapo); }}Copy the code
EmpAction.java
package com.day16.action;
import com.day16.util.BeanOperation;
import com.day16.vo.Emp;
public class EmpAction {
private Emp emp = new Emp();
public void setValue(String val ){// Set the property content
// This is passed to the EmpAction class
// Given the flag emp.ename: Smith, emp should object to the getEmp() method
try {
BeanOperation.setBeanValue(this, val);
} catch (Exception e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}public Emp getEmp(a){
returnemp; }}Copy the code
Reflection with simple Java classes – multi-level VO setup implementation
Now suppose that an employee belongs to a department, a department belongs to a company, a company belongs to a city, a city belongs to a province, and a province belongs to a country. These similar relationships can be configured in multiple levels through strings.
Modify the Dept. Java classes
public class Dept {
private String dname;
private String loc;
private Company company = new Company();
}
Copy the code
Modify the Emp. Java classes
public class Emp {
private String ename;
private String job;
private Dept dept = new Dept();
}
Copy the code
All references are automatically instantiated. Now programs want to settle for single and multilevel.
Modify BeanOperation. Java
package com.day16.util;
/ * * *@authorThis class is mainly responsible for the implementation of automatic VO matching processing operation, itself does not need to be completed by instantiating objects, so the constructor is private */
public class BeanOperation {
private BeanOperation(a){}
/ * * *@paramActionObject represents the current object * of the program class that currently issues the setting request@paramMSG all the properties of the specific content and format "attribute name: | attribute names: content" * * /
public static void setBeanValue(Object actionObject,String msg) throws Exception{
String result [] = msg.split("\ \ |");
for (int i = 0; i < result.length; i++) {
// A split is required for the given attribute name and content
String temp[] = result[i].split(":");
String attribute = temp[0];// Property names, including "XxxAction property and properties of concrete simple AJava classes"
String value = temp[1];// Receive specific content attributes
String fields [] = attribute.split("\ \.");// Split out the attribute information
if(fields.length > 2) {// Multilevel configuration
// If you want to determine the operation object of the property at multiple levels, you should find the content returned by each getter method at one level
Object currentObject = actionObject;// Determine the current object to operate on
for (int j = 0; j < fields.length - 1; j++) {// The corresponding getter returns the object
currentObject = ObjectUtils.getObject(currentObject, fields[j]);
}
ObjectUtils.setObjectValue(currentObject, fields[fields.length - 1], value);
}else{// Single-level configuration
Object currentObject = ObjectUtils.getObject(actionObject,fields[0]);
ObjectUtils.setObjectValue(currentObject, fields[1], value); }}}}Copy the code
Define TestEmpDemo. Java
package com.day16.demo;
import com.day16.action.EmpAction;
public class TestEmpDemo {
public static void main(String[] args) {
String value="Emp. Ename: smi | emp. Job: strack | emp. Dept., dname: finance department | emp.dept.com pany. Name: ZSR | emp.dept.com pany. Address: Beijing";
EmpAction action = newEmpAction(); action.setValue(value); System.out.println(action.getEmp()); }}Copy the code
Such programs can be used normally, belongs to the infinite level configuration.