In addition to providing us with various information about getting classes during the compilation period, Java also allows us to obtain various information about classes during the run period through reflection. Retrieve class information through reflection and after obtaining class information, you can obtain the following related content:
This article will also introduce Java reflection from the above aspects. All codes involved in this article are reflected
First, a Java class is released as the research object for reflection. The content of the class is as follows:
public abstract class FatherObject implements Runnable{ public void doSomething(){ System.out.println("do things..."); }}public class ExampleObject extends FatherObject{ public int age = 30; public String name = "byhieg"; private Integer score = 60; public void printName(){ System.out.println(name); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getScore() { return score; } public void setScore(Integer score) { this.score = score; } public ExampleObject(){ } public ExampleObject(String name){ } public ExampleObject(int age,Integer score){ } @Override public void doSomething() { super.doSomething(); } @Override public void run() { System.out.println("run..."); }}Class object
Our application will use the knowledge point of reflection. We must want to obtain the information of the class at runtime and do some specific operations based on the information of the class. Then, the first thing is to get the information of the class, and a Class object is provided in the JDK to save the information of the class. Therefore, the first step in reflection is to get the Class object. There are two ways to get Class objects in JDK.
The first one is that if you know the name of Class when writing code, you can directly obtain the Class object in the following way:
Class exampleObjectClass = ExampleObject.class;
The second type is that if you don’t know the name of the class when writing the code, but at runtime, you can get a string of the class name, and you can get the Class object in the following way:
Class exampleObjectClass = Class.forName("cn.byhieg.reflectiontutorial.ExampleObject");
Note that this method needs to have 2 conditions. First, the string in forName must be fully qualified name, and second, the Class class must be below the path of the classpath, because the method will throw an exception of ClassNotFoundException.
After obtaining this Class object, you can get various information about the class. Some information has been mentioned at the beginning. Below, let’s talk about the information about the class that has not been mentioned.
Get the name of the class
There are two ways to get the name of the class, one is getName() and the other is getSimpleName(). The first one gets a fully qualified name, and the second one gets a name of this class without a package name. Look at the following example: Class object, which has been obtained through the above code.
String fullClassName = exampleObjectClass.getName(); String simpleClassName = exampleObjectClass.getSimpleName(); System.out.println(fullClassName); System.out.println(simpleClassName); System.out.println(simpleClassName);
The results are as follows:
cn.byhieg.reflectiontutorial.ExampleObjectExampleObject
Get the package name of the class, the parent class and the implementation interface
The package name and parent class of the class can be obtained through the following code.
//Get package information Package aPackage = exampleObjectClass.getPackage(); System.out.println(aPackage); //Get parent class Class superClass = exampleObjectClass.getSuperclass(); System.out.println(superClass.getSimpleName());
The results are as follows:
package cn.byhieg.reflectiontutorialFatherObject
Obviously, getting the return value of the parent class is also a Class object. Then you can use this object to get some information about the parent class, such as judging whether the parent class is an abstract class.
System.out.println("父类是不是抽象类" + Modifier.isAbstract(superClass.getModifiers()));
getModifiers can get class modifiers, thereby obtain class modifiers. Of course, this getModifiers can not only be called Class objects, but Method objects can be called.
You can use the method in the java.lang.reflect.Modifier class to check the type of the modifier:
Modifier.isAbstract(int modifiers);Modifier.isFinal(int modifiers);Modifier.isInterface(int modifiers);Modifier.isNative(int modifiers);Modifier.isPrivate(int modifiers);Modifier.isProtected(int modifiers);Modifier.isPublic(int modifiers);Modifier.isStatic(int modifiers);Modifier.isStrict(int modifiers);Modifier.isSynchronized(int modifiers);Modifier.isTransient(int modifiers);Modifier.isVolatile(int modifiers);
In addition, we can also get the interface implemented by the parent class
//Get the interface Class[] classes = superClass.getInterfaces(); System.out.println("Interfaces of parent class" + classes[0]);Because Java classes can implement many interfaces, they use arrays, but when actually using them, you need to first determine the length of the array.
Below, we will focus on explaining the above listed content.
Constructor
Using Java reflection, you can get a class constructor, and dynamically create an object at runtime based on the constructor. First, Java obtains an instance of the constructor by:
//ConstructorConstructor[] constructors = exampleObjectClass.getConstructors(); for (Constructor constructor: constructors){ System.out.println(constructor.toString()); }The results are as follows:
public cn.byhieg.reflectiontutorial.ExampleObject(int,java.lang.Integer)public cn.byhieg.reflectiontutorial.ExampleObject(java.lang.String)public cn.byhieg.reflectiontutorial.ExampleObject()
If you know the parameter type of the constructor to access in advance, you can use the following method to obtain the specified constructor, as follows:
Constructor constructor = exampleObjectClass.getConstructor(String.class); System.out.println(constructor.toString());
The result is obviously:
public cn.byhieg.reflectiontutorial.ExampleObject(java.lang.String)
Another constructor can also be obtained in the following way
Constructor constructor = exampleObjectClass.getConstructor(int.class,Integer.class); System.out.println(constructor.toString());
In addition, if we do not know the constructor parameters and can only get all the constructor objects, we can obtain the parameters that each constructor uses as follows:
Constructor[] constructors = exampleObjectClass.getConstructors(); for (Constructor constructor : constructors){ Class[] parameterTypes = constructor.getParameterTypes(); System.out.println("Constructor parameters are as follows================================================================================================================================== for (Class clz : parameterTypes){ System.out.println("Parametertype" + clz.toString()); } }The results are as follows:
The constructor parameters are as follows================================== Parameter type class java.lang.String constructor parameters are as follows========================== Parameter type int parameter type class java.lang.Integer
Here, it can be seen that the parameterless construction method does not print the result. The Class object of the basic type and the Class object of the reference type are different.
Now, an object can be created dynamically based on various information from the constructor.
Object object = constructor.newInstance(1,100); System.out.println(object.toString());
There are two conditions for creating an object. The first is created through a parameter constructor. The second is that the constructor object must be obtained through the getConstructor that passes in parameter information.
The first condition is that for objects that can be created without parameter construction methods, there is no need to obtain the constructor object. The Class object calls the newInstance() method and creates the object directly.
The second condition is that the constructor object must be obtained through the form exampleObjectClass.getConstructor(String.class); It would be wrong to get the constructor array through getConstructors and then call the specified constructor object to create the object in JDK1.8. But JDK1.6 is normal.
variable
Using Java reflection, you can get variable information of a class at runtime, and you can create an object and set its variable value according to the above method. First, all public variables are obtained by following the following method:
Field[] fields = exampleObjectClass.getFields(); for (Field field : fields){ System.out.println("Variable is: " + field.toString()); }The results are as follows:
The variable is: public int cn.byhieg.reflectiontutorial.ExampleObject.age The variable is: public java.lang.String cn.byhieg.reflectiontutorial.ExampleObject.name
Obviously, all the obtained public variables are public, and the above private variable score is not obtained.
The same way as the constructor is obtained, we can specify a parameter name and then get the specified variable:
Field field = exampleObjectClass.getField("age"); System.out.println("Variable is:" + field.toString());The name obtained by the toString method of the above variable is too long. Java provides the getName method to the Field class, which returns the name of the variable written in the class. The above code can be changed to field.getName().
Reflection not only provides a way to get variables, but also provides a way to set variable values. By following the following method, you can change the variable value of a dynamically generated class:
ExampleObject object = ((ExampleObject) constructor1.newInstance("byhieg")); System.out.println("The original age is" + object.age); field.set(object,10); System.out.println("The age after the change is" + object.age);The results are as follows:
The original age is 30 and the age after the change is 10
According to the above code, you can get a Field object named age, then call the set method of the object, pass an object and the value to be changed, and then you can change the value of the object. Note that this method is not only useful for member variables, but also for static variables. Of course, if it is a static variable, it is OK to pass null without passing the object.
method
In addition to providing us with variable information of the class, Java reflection also provides us with method information. Reflection allows us to obtain method name, method parameters, method return type, and calling methods.
First, get the method through the following code:
//The public method of the output class Method[] methods = exampleObjectClass.getMethods(); for (Method method : methods){ System.out.println("method = "+ method.getName()); }Code that looks familiar like getting variables. GetName is called directly here to get the method name written in the class. Having written this, you should naturally think that Java also provides specific methods based on parameters.
Method method = exampleObjectClass.getMethod("setAge",int.class); System.out.println(method.getName());The difference here is that the getMethod method also needs to pass in parameter type information, reflecting provides a method to obtain method parameters and return type. Examples of obtaining method parameters are as follows:
Method method = exampleObjectClass.getMethod("setAge",int.class); System.out.println(method.getName()); for (Class clz : method.getParameterTypes()){ System.out.println("Parameter of method" + clz.getName()); }The results are as follows:
The parameter int of the setAge method
An example of obtaining the method return type is as follows:
System.out.println(method.getReturnType().getName());
The results are as follows:
void
In addition, Java reflection supports methods obtained through invoke calls. Examples are as follows:
method.invoke(exampleObjectClass.newInstance(),1);
The first parameter invoke is this object, and the second parameter is a variable-length array, and the parameters of the method are passed in. Like Field objects, for static methods, you can pass null and call static methods.
Private variables and private methods
The above method can only obtain public methods and variables, but cannot obtain non-public modified methods and variables. Java provides additional methods to obtain non-public variables and methods. That is, private variables and methods are obtained through getDeclaredFields and getDeclaredMethods methods. It also supports the use of getDeclaredField (variable name) and getDeclaredMethod (method name) to obtain the specified variable name and method name. However, the Field objects and Method objects obtained in this way cannot be directly used. These objects must be called setAccessible(true) for normal use. The following method can be the same as mentioned above.
annotation
First write a class containing annotations:
@MyAnnotation(name="byhieg",value = "hello world")public class AnnotationObject { @MyAnnotation(name="field",value = "variable") public String field; @MyAnnotation(name="method",value = "method") public void doSomeThing(){ System.out.println("Do something"); } public void doOtherThing(@MyAnnotation(name="param",value = "param") String param){ }}@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation { public String name(); public String value();}Java provides us with information about obtaining class annotations at runtime, and we can get class annotations, method annotations, parameter annotations, and variable annotations.
Like the above acquisition method, Java provides two acquisition methods. One is to obtain all annotations and return an array, and the second is to specify the specified annotations.
Let’s take a class annotation as an example to explain the following two ways of obtaining.
Class clz = AnnotationObject.class; Annotation[] annotations = clz.getAnnotations(); Annotation annotation = clz.getAnnotation(AnnotationObject.class);
Then, subsequent processing can be performed based on the obtained annotation. The following is an example of processing:
for (Annotation annotation : annotations){ if (annotation instanceof MyAnnotation){ MyAnnotation myAnnotation = (MyAnnotation)annotation; System.out.println("name: " + myAnnotation.name()); System.out.println("value:" + myAnnotation.value()); } }The above class annotations are obtained by calling getAnnotations using Class object. The method annotations and variable annotations are the same. I call getDeclaredAnnotations using method objects and field objects respectively to get annotations. I don’t have much to say. See the reflection code for example
Parameter annotations are a relatively troublesome item. The acquisition method is compared. The first step is to obtain the method object first and call getParameterAnnotations. However, this return value is a two-dimensional array, because the method object has many parameters, and each parameter may have many annotations. Examples are as follows:
Method method1 = clz.getMethod("doOtherThing",String.class); Annotation[][] annotationInParam = method1.getParameterAnnotations(); Class[] params = method1.getParameterTypes(); int i = 0; for (Annotation[] annotations: annotationInParam){ Class para = params[i++]; for (Annotation annotation : annotations){ if(annotation instanceof MyAnnotation){ MyAnnotation myAnnotation = (MyAnnotation) annotation; System.out.println("param: " + para.getName()); System.out.println("name : " + myAnnotation.name()); System.out.println("value :" + myAnnotation.value()); } } }Generics
Because Java generics are implemented through erasing, it is difficult to directly obtain information about the specific parameterized type of generics, but we can obtain generic information through an indirect form using reflection. For example, the following class:
public class GenericObject { public List<String> lists; public List<String> getLists() { return lists; } public void setLists(List<String> lists) { this.lists = lists; }}If a method returns a generic class, we can call getGenericReturnType through the method object to getGenericReturnType to get what the specific parameterization type of this generic class is. Look at the following code:
Class clz = GenericObject.class; Method method = clz.getMethod("getLists"); Type genericType = method.getGenericReturnType(); if(genericType instance of ParameterizedType){ ParameterizedType parameterizedType = ((ParameterizedType) genericType); Type[] types = parameterizedType.getActualTypeArguments(); for (Type type : types){ Class actualClz = ((Class) type); System.out.println("Parameterization type is: " + actualClz); } }The results are as follows:
参数化类型为: class java.lang.String
The steps are a bit cumbersome, so the following explanation is:
I did get specific information about the generics by looking at the results.
If no method returns a generic type, then we can also obtain the parameterized type of the generic type by the method's parameter as a generic class, such as the setLists method in the above class. Examples are as follows:
Method setMethod = clz.getMethod("setLists", List.class); Type[] genericParameterTypes = setMethod.getGenericParameterTypes(); for (Type genericParameterType: genericParameterTypes){ System.out.println("GenericParameterTypes is: " + genericParameterType.getTypeName()); if(genericParameterType instance of ParameterizedType){ ParameterizedType parameterizedType = ((ParameterizedType) genericParameterType); System.out.println("ParameterizedType is:" + parameterizedType.getTypeName()); Type types[] = parameterizedType.getActualTypeArguments(); for (Type type : types){ System.out.println("Parameterized type is: " + ((Class) type).getName()); } } }The execution results are as follows:
GenericParameterTypes is: java.util.List<java.lang.String>ParameterizedType is: java.util.List<java.lang.String> Parameterized type is: java.lang.String
Because the method's parameters may have more than one generic type, we getGenericParameterTypes to get an array, and we need to determine whether each element has a parameterized type. The subsequent steps are similar to those above, so I won’t say much.
If even the method parameters do not contain generic classes, then only the last case is left, through the variable type, that is, the Field class is used. Examples are as follows:
Field field = clz.getField("lists"); Type type = field.getGenericType(); if (type instance of ParameterizedType){ ParameterizedType parameterizedType = ((ParameterizedType) type); Type [] types = parameterizedType.getActualTypeArguments(); for (Type type1 : types) { System.out.println("Parameterized type: " + ((Class) type1).getTypeName()); } }The principle is the same as above, except that the Type object is through field.getGenericType(), so I won't say much about the remaining operations.
This is the introduction to obtaining the parameterized type of generics through reflection.
Array
Java reflection can operate on an array, including creating an array, accessing values in an array, and obtaining a Class object of an array.
Let’s talk about it simply, creating an array and accessing the values in the array: using the Array class in reflection is the one below the reflect package.
//Create an array of int type with a length of 3 int[] intArray = (int[])Array.newInstance(int.class,3); //Assign a value to the array through reflection for (int i = 0 ; i < intArray.length;i++){ Array.set(intArray,i,i + 2); }//Array in the form of reflection, get the value in the array for (int i = 0 ; i < intArray.length;i++){ System.out.println(Array.get(intArray,i)); }The above is to create an array and access the values in the array using reflection.
For Class objects that get an array, you can simply use int[].class , or use Class.forName, which is a strange way to write:
Class clz = Class.forName("[I"); System.out.println(clz.getTypeName());The result is:
int[]
The string in this forName, [ represents an array, I represent an int, float is F , double is D , etc. If you want to get an array of ordinary objects, use the following form:
Class stringClz = Class.forName("[Ljava.lang.String;");
[ Say it is an array, the right side of L is the class name, and the right side of type is a ; ;
This way to get the Class object of the array is too cumbersome.
After obtaining the Class object of the array, some of its unique methods can be called, such as calling getComponentType to obtain the type information of array members. For example, an int array is a member type, which is int.
System.out.println(clz.getComponentType().getTypeName());
The result is int
Summarize
This time, the various applications of reflection end with this, and there may be in-depth knowledge explanations in the future. For specific code, you can look at the reflection code
In the src package, there are various classes, and in the test class, it is access to these classes.
The above is all the content of this article. I hope that the content of this article will be of some help to everyone’s study or work. I also hope to support Wulin.com more!