1. General
1.1 concept of reflection
Reflection is the key to being regarded as a dynamic language. Reflection mechanism allows programs to obtain the internal information of any class with the help of Reflection API during execution, and can directly operate the internal properties and methods of any object.
After loading the Class, an object of Class type is generated in the method area of heap memory (a Class has only one Class object), which contains the complete structure information of the Class. We can see the structure of the Class through this object. This object is like a mirror, through which we can see the structure of the Class. Therefore, we vividly call it reflection.
1.2 application
Determine the class of any object at run time
Construct an object of any class at run time
Judge the member variables and methods of any class at run time
Get generic information at run time
Call the member variables and methods of any object at run time
Processing annotations at run time
Generate dynamic proxy
1.3 examples of reflection
Person.java:
package com.wzc.java; public class Person { private String name; public int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person() { } private Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public void show(){ System.out.println("Hello, I'm alone"); } private String showNation(String nation){ System.out.println("My nationality is" + nation); return nation; } }
//Operation on Person before reflection @Test public void test1(){ //1. Create the object of Person class Person p1 = new Person("Tom",12); //2. Call the properties and methods through the object p1.age = 10; System.out.println(p1.toString()); p1.show(); //Outside the Person class, its internal private structure cannot be called through the object of the Person class //For example: name, showNation() and private constructor } //With reflection, the operation of Person @Test public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { Class clazz = Person.class; //1. Create an object of Person class through reflection Constructor cons = clazz.getConstructor(String.class, int.class); Object obj = cons.newInstance("Tom", 12); Person p = (Person)obj; System.out.println(p.toString()); //2. Call the object to specify the attribute method through reflection //Call properties Field age = clazz.getDeclaredField("age"); age.set(p,10); System.out.println(p.toString()); //Call method Method show = clazz.getDeclaredMethod("show"); show.invoke(p); System.out.println("*************************************"); //Reflection allows you to call the private structure of the Person class. For example, private constructors, methods, and properties Constructor cons1 = clazz.getDeclaredConstructor(String.class); cons1.setAccessible(true); Person p1 = (Person)cons1.newInstance("Jerry"); System.out.println(p1); //Call private property Field name = clazz.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"LaoLiu"); System.out.println(p1); //Call private method Method showNation = clazz.getDeclaredMethod("showNation", String.class); showNation.setAccessible(true); String nation = (String)showNation.invoke(p1,"China");//Equivalent to string nation = P1 Shownation ("China") System.out.println(nation); }
2. Understand the Class and get the instance of Class
2.1 understanding of class
1. Class loading process: the program passes javac Exe command will generate one or more bytecode files (. End of class). Then we use Java Exe command to interpret and run a bytecode file. It is equivalent to loading a bytecode file into memory. This process is called class loading. The class loaded into memory is called the runtime class. This runtime class is used as an instance of class.
2. In other words, an instance of Class corresponds to a runtime Class.
3. Runtime classes loaded into memory will be cached for a certain time. Within this time, we can get this runtime class in different ways.
2.2 method of obtaining Class instance
@Test public void test3() throws ClassNotFoundException { //Method 1: call the properties of the runtime class: class Class clazz1 = Person.class; System.out.println(clazz1); //Method 2: call getClass() through the object of the runtime class Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2); //Method 3: call the static method of Class: forname (striding classpath) Class clazz3 = Class.forName("com.wzc.java.Person"); System.out.println(clazz3); System.out.println(clazz1 == clazz2); //true points to the same address and corresponds to the same class System.out.println(clazz2 == clazz3); //true //Method 4: use class loader ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.wzc.java.Person"); System.out.println(clazz4); System.out.println(clazz4 == clazz1); //true }
There are some types of Class objects:
(1) Class: external class, member (member internal class, static internal class), local internal class, anonymous internal class
(2) interface: interface
(3) []: array
(4) enum: Enumeration
(5) Annotation: annotation @ interface
(6) primitive type: basic data type
(7)void
Class c1 = Object.class; Class c2 = Comparable.class; Class c3 = String[].class; Class c4 = int[][].class; Class c5 = ElementType.class; Class c6 = Override.class; Class c7 = int.class; Class c8 = void.class; Class c9 = Class.class; int[] a = new int[10]; int[] b = new int[100]; Class c10 = a.getClass(); Class c11 = b.getClass(); // As long as the array element type is the same as the dimension, it is the same Class System.out.println(c10 == c11); //true
3. Class loading process and ClassLoader
3.1 loading process of class
Function of class loader:
Class loading: load the bytecode content of the class file into memory, convert these static data into the runtime data structure of the method area, and then generate a Java. Net file representing this class in the heap Lang. class object, as the access entry of class data in the method area.
Class caching: the standard Java se class loader can find classes as required, but once a class is loaded into the class loader, it will remain loaded (cached) for a period of time. However, the JVM garbage collection mechanism can recycle these class objects.
3.2 ClassLoader understanding
Class loader is used to load classes into memory. The JVM specification defines loaders for classes of the following types.
Learn about class loaders:
@Test public void test1(){ //For custom classes, use the system class loader to load them ClassLoader classLoader = ClassLoadertest.class.getClassLoader(); System.out.println(classLoader); //System loader //Call getParent() of the system class loader: get the extended class loader ClassLoader classLoader1 = classLoader.getParent(); System.out.println(classLoader1);//extensions class loader //Calling getParent() of extender loader class: unable to get boot class loader //The boot class loader is mainly responsible for loading the core class library of java, and cannot load custom classes ClassLoader classLoader2 = classLoader1.getParent(); System.out.println(classLoader2);//null does not mean there is no, but the bootstrap class loader cannot be obtained ClassLoader classLoader3 = String.class.getClassLoader(); System.out.println(classLoader3); //null boot class loader }
3.3 loading files with loader
For example, load JDBC files (two methods):
@Test public void test2() throws Exception { Properties pros = new Properties(); //At this time, the file is under the current module by default //Method 1 for reading configuration files: // FileInputStream fis = new FileInputStream("jdbc.properties"); // FileInputStream fis = new FileInputStream("src\\jdbc1.properties"); // pros.load(fis); //The second way to read the configuration file is to use classloader //The default identification of the configuration file is: under src of the current module ClassLoader classLoader = ClassLoadertest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("jdbc1.properties"); pros.load(is); String user = pros.getProperty("username"); String password = pros.getProperty("password"); System.out.println("user = " + user + ",password = " + password); }
4. Create the object of the runtime class
4.1 get the object of runtime class through reflection
@Test public void test1() throws IllegalAccessException, InstantiationException { Class<Person> clazz = Person.class; /*newInstance():Call this method to create the object of the corresponding runtime class. An empty argument constructor of the class was called internally To create an object of a runtime class using this method: 1.The runtime must provide an empty argument constructor 2.Empty argument constructor has sufficient access rights. Usually public A public null parameter constructor is required in the javabean 1.It is convenient to create objects of runtime classes through reflection 2.When a subclass inherits this running class, it is guaranteed that the parent class has this constructor when super() is called by default */ Person obj = clazz.newInstance(); //This method is outdated after Java 9 System.out.println(obj); }
4.2 experience the dynamics of reflection
java is a dynamic language. It can change its structure according to some conditions at runtime. For example, according to some judgment statements, the creation of objects can not always be the same. Reflection mechanism can create corresponding classes in this dynamic language.
//Experience the dynamics of reflection @Test public void test2(){ for (int i = 0; i < 100; i++) { int num = new Random().nextInt(3); // 0,1,2 String classPath = ""; switch (num){ case 0: classPath = "java.util.Date"; break; case 1: classPath = "java.lang.Object"; break; case 2: classPath = "com.wzc.java.Person"; break; } try { Object instance = getInstance(classPath); System.out.println(instance); } catch (Exception e) { e.printStackTrace(); } } } //Create an object of the specified class. classpath: Specifies the full class name of the class public Object getInstance(String classPath) throws Exception { Class Clazz = Class.forName(classPath); return Clazz.newInstance(); }
5. Get the complete structure of the runtime class
5.1 get the attribute structure of the current class
@Test public void test1(){ Class clazz = Person.class; //Get attribute structure //getFields(): get the attributes declared as public access rights in the current runtime class and parent class Field[] fields = clazz.getFields(); for (Field f : fields) { System.out.println(f); } System.out.println(); //Getdeclaraedfields(): get all the properties declared in the current runtime class. (excluding properties declared in the parent class) Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields) { System.out.println(f); } } @Test public void test3(){ Class clazz = Person.class; Field[] declaredFields = clazz.getDeclaredFields(); for(Field f:declaredFields){ //1. Permission modifier int modifier = f.getModifiers(); System.out.print(Modifier.toString(modifier) + ", "); //2. Data type Class type = f.getType(); System.out.print(type.getName() + ", "); //3. Variable name String fName = f.getName(); System.out.print(fName); System.out.println(); } }
5.2 get the method structure of the current class
@Test public void test1(){ Class clazz = Person.class; //getMethods(): get the methods declared as publi permission in the current runtime class and all its parent classes Method[] methods = clazz.getMethods(); for(Method m:methods){ System.out.println(m); } System.out.println(); //Getdeclaraedmethods(): get all the methods declared in the current runtime class. (excluding those declared in the parent class) Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method m: declaredMethods){ System.out.println(m); } } //@Xxxx //Permission modifier return value type method name (parameter type 1, parameter name 1...) throws XxxException() @Test public void test2(){ Class clazz = Person.class; Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method m : declaredMethods){ //1. Get the annotation of the method declaration Annotation[] annos = m.getAnnotations(); for(Annotation a : annos){ System.out.print(a); } //2. Permission modifier System.out.print(Modifier.toString(m.getModifiers()) + ", "); //3. Return value type System.out.print(m.getReturnType().getName() + ", "); //4. Method name System.out.print(m.getName()); //5. Formal parameter list System.out.print("("); Class[] parameterTypes = m.getParameterTypes(); if(!(parameterTypes == null && parameterTypes.length == 0)){ for(int i=0; i<parameterTypes.length; i++){ if(i==parameterTypes.length - 1){ System.out.print(parameterTypes[i].getName() + " agrs_" + i); break; } System.out.print(parameterTypes[i].getName() + " agrs_" + i + ","); } } System.out.print(")"); //6. Exceptions thrown Class[] exceptionTypes = m.getExceptionTypes(); if(exceptionTypes.length > 0){ System.out.print("throws "); for (int i=0; i<exceptionTypes.length; i++){ if(i == exceptionTypes.length - 1){ System.out.print(exceptionTypes[i].getName()); break; } System.out.print(exceptionTypes[i].getName() + ", "); } } System.out.println(); } }
5.3 get constructor of current class
@Test public void test1(){ Class clazz = Person.class; //getConstructors(): get the constructor declared as public in the current runtime class Constructor[] constructors = clazz.getConstructors(); for(Constructor c : constructors){ System.out.println(c); } System.out.println(); //Getdeclaraedconstructors(): get all constructors declared in the current running class Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for(Constructor c : declaredConstructors){ System.out.println(c); } }
5.4 get the parent class and generic type of the current class
//Gets the parent class of the runtime @Test public void test2(){ Class clazz = Person.class; Class superclass = clazz.getSuperclass(); System.out.println(superclass); } //Gets or runs the parent class with generics @Test public void test3(){ Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); System.out.println(genericSuperclass); } //Gets the generic type that runs the parent class with the generic type @Test public void test4(){ Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) genericSuperclass; //Get generic type Type[] actualTypeArguments = paramType.getActualTypeArguments(); System.out.println(actualTypeArguments[0]); System.out.println(((Class)actualTypeArguments[0]).getName()); }
5.4 get the annotation of the interface, package and declaration of the current class
//Gets the interface implemented by the runtime class @Test public void test5(){ Class clazz = Person.class; Class[] interfaces = clazz.getInterfaces(); for(Class c : interfaces){ System.out.println(c); } System.out.println(); //Gets the interface of the runtime parent class Class[] interfaces1 = clazz.getSuperclass().getInterfaces(); for(Class c : interfaces1){ System.out.println(c); } } //Gets the package where the runtime class is located @Test public void test6(){ Class clazz = Person.class; Package aPackage = clazz.getPackage(); System.out.println(aPackage); } //Gets the annotation of the runtime class declaration @Test public void test7(){ Class clazz = Person.class; Annotation[] annotations = clazz.getAnnotations(); for(Annotation annos : annotations){ System.out.println(annos); } }
6. Get the specified structure of the runtime class
6.1 get the specified properties of the runtime class
//No @Test public void testFiled() throws Exception { Class clazz = Person.class; //Create an object for the runtime class Person p = (Person) clazz.newInstance(); //Get the specified property: the property in the runtime class is required to be declared public //This method is not usually used Field id = clazz.getField("id"); //Sets the value of the current property //set(): parameter 1: indicates which object's property is set. Parameter 2: how much this property value is set id.set(p,1001); //Gets the value of the current property //get(): parameter 1: get the current property value of which object int pId = (int) id.get(p); System.out.println(pId); } //Yes //The specified property in the action runtime class @Test public void test2() throws Exception { Class clazz = Person.class; //Create an object for the runtime class Person p = (Person)clazz.newInstance(); //1. Getdeclaraedfield (string fieldname): get the attribute of the specified variable name in the runtime class Field name = clazz.getDeclaredField("name"); //2. Ensure that the current attribute is accessible name.setAccessible(true); //3. Get and set the property value of the specified object name.set(p, "Tom"); System.out.println(name.get(p)); }
6.2 get the specified method of the runtime class
//Yes //The specified method in the operation runtime class @Test public void test3() throws Exception { Class clazz = Person.class; //Create runtime objects Person p = (Person)clazz.newInstance(); //Gets a specified method //getDeclaredMethod(): parameter 1: indicates the name of the obtained method; parameter 2: indicates the formal parameter list of the obtained method Method show = clazz.getDeclaredMethod("show", String.class); //2. Ensure that the current method is accessible show.setAccessible(true); //3. invoke() of calling method: parameter 1: caller of method; parameter 2: argument assigned to method parameter //The return value of invoke() is the return value of the method called in the corresponding class. Object returnValue = show.invoke(p, "CHN"); System.out.println(returnValue); System.out.println("***************How to call static methods**************"); Method showDesc = clazz.getDeclaredMethod("showDesc"); showDesc.setAccessible(true); //Object returnVal = showDesc.invoke(null); // The Person class has already been loaded Object returnVal = showDesc.invoke(Person.class); System.out.println(returnVal); }
6.3 get the specified constructor of the runtime class
//Calls the specified constructor in the runtime class @Test public void testConstructor() throws Exception{ Class clazz = Person.class; Constructor constructor = clazz.getDeclaredConstructor(String.class); constructor.setAccessible(true); Person per = (Person) constructor.newInstance("Tom"); System.out.println(per); }
reference material:
[1] Shang Silicon Valley song Kanghong java basic course