Java reflection mechanism and Application
1. Java reflection
In the running state, for any class, you can get all the properties and methods of the class, and for any object, you can call any of its methods and properties (including private methods and properties). This dynamically obtained information and the function of dynamically calling the methods of the object are called the reflection mechanism of java language.
2. Java program running process
java source file (. java file) – > compiled by Javac compiler – > binary bytecode file (. Class file) – > JVM class loader loading – > interpreter interpretation – > machine code (machine understandable code) – > operating system platform
3. Java reflection function and principle
3.1 reflection
Through reflection, you can dynamically create objects and call their properties at run time without knowing who the running object is at compile time in advance.
3.2 reflection principle
In short, it is to obtain the properties, methods and other information of class objects through decompilation.
The reflection mechanism of Java is that it is not sure which class is loaded at compile time, but it is loaded, detected and self reviewed when the program is running. Use classes that are not known at compile time.
Decompile: class–>. java
Note: when Jvm loads bytecode files from local disk into Jvm memory, Jvm will automatically create a class object. That is, a class will only produce one class object.
Reason: class loading mechanism - parent delegation mechanism
4. Class loading mechanism - parental delegation mechanism
The JVM provides a three-tier ClassLoader:
-
Bootstrap classloader: it is mainly responsible for loading the core class library (java.lang. * etc.) and constructing ExtClassLoader and APPClassLoader.
-
ExtClassLoader: mainly responsible for loading some extended jar s in jre/lib/ext directory.
-
AppClassLoader: mainly responsible for loading the main function class of the application.
The class loading process under the parental delegation mechanism is shown in the figure below:
When considering the existence of a user-defined class loader, the first step in loading a class is to check whether the class has been loaded from the user-defined class loader. If it has not been loaded, delegate upward and get the parent class constructor AppClassLoader loader for inspection. If it has not been loaded, delegate upward in turn, Constantly check whether the parent class loader has loaded the class. If it has been loaded, you do not need to load it again and return directly. If the class is not loaded after being checked by the bootstrap classloader, load the class from the parent class downward. If the bootstrap classloader cannot load this class, it will be loaded by the subclass loader and loaded downward in turn.
Role of parental delegation mechanism:
- Avoid secondary loading of the same class
- Prevent the core class library API from being modified
5. Java reflection usage
5.1 three ways to obtain class objects
- Get the Class object through the static method forName in the Class
Class clazz1 = Class.forName("Fully qualified class name");
- Pass the class name class
Class clazz2 = Demo.class;
- Get the bytecode file object of the class through the instance of the class
Class clazz3 = p.getClass();
5.2 reflection acquisition class attributes, methods and construction methods
public class TargetDemo { public TargetDemo (){} public TargetDemo (String str){ this.str = str; System.out.println("Execution constructor method"); } public String str = "hello"; private String username; private int age; public void print(){ System.out.println("TargetDemo"); } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class TestDemo { public static void main(String[] args) { try { //Get class object Class<?> target = Class.forName("com.torlesse.consumer.test.TargetDemo"); //Getting the public part of the class object property cannot access the private part for (Field field : target.getFields()) { System.out.println(field.getName()); } //Get constructor Constructor<?> targetDeclaredConstructor = target.getDeclaredConstructor(String.class); Object o = targetDeclaredConstructor.newInstance("demo"); System.out.println(o); //Instantiate object Object o1 = target.newInstance(); //Acquisition method Method method = target.getMethod("print"); method.invoke(o1,null); } catch (Exception e) { e.printStackTrace(); } } }
result:
6. Run the specified package to get the specified annotation class
Scheme usage: reflections framework
Dependent import:
<dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.11</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>21.0</version> </dependency>
//Tag class annotation @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface JobClassInterface { }
//Annotation of marking method @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface JobMethodInterface { String jobName(); }
//Enter the package name to scan Reflections f = new Reflections("com.torlesse.xxx.xxx"); //Input target annotation class Set<Class<?>> set = f.getTypesAnnotatedWith(JobClassInterface.class); Iterator<Class<?>> iterator = set.iterator(); while (iterator.hasNext()){ Class<?> next = iterator.next(); for (Method method : next.getMethods()) { for (Annotation declaredAnnotation : method.getDeclaredAnnotations()) { if(declaredAnnotation instanceof JobMethodInterface){ String targetName = ((JobMethodInterface)declaredAnnotation).jobName(); if(targetName.equals(jobName)){ method.invoke(next.newInstance(), null); return; } } } } }