Reflection mechanism (hard to crack, check it out)
You can view the specific information about a class that has been loaded to a VM based on its class name. When people see money, they will have the information and appearance of RMB in their mind.
Dynamic and static languages
Dynamic languages
- A language whose structure can be changed at run time: for example, new functions, objects, and even code can be introduced, existing functions can be deleted, or other structural changes can be made. In layman’s terms, code can change its structure at run time depending on certain conditions.
- Main dynamic languages: Object-C, C#, JavaScript, PHP, Python, etc.
Static language
- The equivalent of dynamic languages, languages with immutable run-time structures, are static languages. Such as Java, C, C++.
- Java is not a dynamic language, but Java can be called a “quasi-dynamic language.” That is, Java is dynamic, and we can use reflection to get features like dynamic languages. The dynamic nature of Java makes programming more flexible!
Java Reflection
Reflection is considered the key to a dynamic language. Reflection allows programs to use the Reflection API to retrieve internal information about any class at runtime and to directly manipulate internal properties and methods of any object.
After the Class is loaded, an object of type Class is generated in the method area of heap memory (each 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 you can see the structure of the class, so we call it a reflection.
Functionality provided by the Java reflection mechanism
- Determine the class to which any object belongs at run time
- Constructs an object of any class at run time
- Determine which member variables and methods any class has at run time
- Call the member variables and methods of any object at run time
- You can handle annotations
- Generating dynamic proxies
Advantages and disadvantages of Java reflection
advantages
- Dynamic object creation and compilation can be achieved, reflecting a great deal of flexibility
disadvantages
- Performance is affected. Using reflection is basically an interpretation operation where we can tell the JVM what we want to do, and it meets our requirements. This type of operation is always slower than performing the same operation directly
Class Class
Objects can look in the mirror and get information about a class’s properties, methods and constructors, and what interfaces a class implements.
For each Class, the JRE reserves an invariant object of type Class for it. A Class object contains a particular structure (Class/interface/enum/annotation/primitive type/void / []) of the relevant information.
package com.volcano.reflection;
import java.lang.annotation.ElementType;
public class TestReflection2 {
public static void main(String[] args) {
Class a = Object.class;/ / class
Class b = Runnable.class;/ / interface
Class c = String[].class;// An array is a class as long as the element type is the same as the dimension
Class d = int[][].class;// A two-dimensional array
Class e = Override.class;/ / comment
Class f = ElementType.class;// Enumeration type
Class g = Integer.class;// Basic data type
Class h = void.class;//void
Class i = Class.class;//ClassSystem.out.println(a); System.out.println(b); System.out.println(c); System.out.println(d); System.out.println(e); System.out.println(f); System.out.println(g); System.out.println(h); System.out.println(i); }}Copy the code
class java.lang.Object
interface java.lang.Runnable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
Copy the code
- Class is itself a Class
- Class objects can only be created by the system
- A loaded Class will only have one Class instance in the JVM
- A Class object corresponds to one loaded into the JVM
.class
file - Each instance of a Class remembers which Class instance it was generated from
- Class provides a complete view of all loaded structures in a Class
- The Class Class is the root of Reflection, and for any Class that you want to dynamically load and run, you have to get the corresponding Class object first
Class Object defines the following methods, which are inherited by all subclasses: Public Final Class getClass(); The return type of the above method is a Class Class. This Class is the source of Java reflection. In fact, the so-called reflection can be understood from the results of the program.
Person p = new Person();
Class cls = p.getClass();// Contains all the information for the Person class
Copy the code
Commonly used method
The method name | function |
---|---|
static Class forName(String name) |
Gets the Class object based on the full Class name (package name + Class name) of the Class |
Object newInstance() |
Call the no-argument constructor to create an instance that returns the Class object |
String getName() |
Gets the full Class name represented by the Class object (Class, interface, array Class, void) |
String getSimpleName() |
Same as above, but only class name, no prefixed package name |
Class[] getInterfaces() |
Gets the interface of the current Class object |
ClassLoader getClassLoader() |
Gets the classloader for the class |
Class getSuperClass() |
Gets the Class object of the parent Class of the current Class object |
Constructor[] getConstructors() |
Gets the constructor of the current Class object |
Constructor getConstructor(Class ... paramTypes) |
Gets the specified argument type constructor for the current Class object |
Field[] getFields() |
Gets all the Public properties of the current Class object |
Field getField(String name) |
Gets the Public property specified by the current Class object |
Field[] getDeclaredFields() |
Gets all attributes of the current Class object |
Method[] getMethods() |
Get all methods of the current Class object (including inherited ones) |
Method[] getDeclaredMethods() |
Get all the methods of the current Class object (by itself) |
Method getMethod(String name, Class ... paramTypes) |
Gets the corresponding method of the current Class objectgetMethod("setName",String.class); |
Create class method
-
If a specific class is known, it is most secure and efficient to use the class attribute to create the class
Class cla = String.class; Copy the code
-
If you know an instance of a class, use the instance’s getClass() method
Class clb = p.getClass(); Copy the code
-
Given the full Class name of a Class, the static method forName() of Class may throw a ClassNotFoundException(most used)
Class clc = Class.forName("The package name. A Person");// The full path of the class is required Copy the code
-
Built-in primitive data types can be used directly by class names. Type
Class cld = Integer.TYPE;// Result: int Copy the code
-
Create by ClassLoader (no requirement)
ClassLoader cl = this.getClass().getClassLoader(); Class c4 = cl.loadClass("Full path of class"); Copy the code
Class loader
- The class loader loads the bytecode content of the class file into memory, converts this static data into a run-time data structure for the method area, and then generates a java.lang. class object representing this class in the heap as an access point for the class data in the method area
- Class caching: The standard JavaSE class loader can find classes on demand, but once a class is loaded into the class loader, it stays loaded (cached) for a while. However, the JVM garbage collection mechanism can reclaim these Class objects
Classification of class loaders
- Bootstrap classloader (BootstrapClassLoader)
- Written in C++, is the JVM class loader, responsible for the Java platform core library, used to load the core class library. structure
ExtClassLoader
andAppClassLoader
, the loader is not available directly - Java platform core library: JRE \lib\rt.jar, open with compression software, which is the class we usually want to learn. This JRE is a public JRE, not a dedicated JRE in the JDK directory
- Written in C++, is the JVM class loader, responsible for the Java platform core library, used to load the core class library. structure
- Extended class loader (ExtClassLoader)
- To be responsible for thejre\lib\extJar package or
-D java.ext.dirs
The jar in the specified directory is wrapped into the working library - Here the JRE is also the public JRE
- To be responsible for thejre\lib\extJar package or
- System class loader (AppClassLoader)
- To be responsible for the
java -classpath
or-D java.class.path
The class and JAR wrapper in the directory indicated is the most commonly used loader
- To be responsible for the
-
Custom loader (CustomClassLoader)
package com.volcano.reflection;
public class TestReflection4 {
public static void main(String[] args) {
// Get the system class loader
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
// Get the extended class loader
classLoader = classLoader.getParent();
System.out.println(classLoader);
// Get the boot class loader (which is directly unavailable)
classLoader = classLoader.getParent();
System.out.println(classLoader);
// Tests which classloader is loading the current class -- bootstrap the classloader
System.out.println(TestReflection4.class.getClassLoader());
// Test which class loader the JDK built-in classes are loaded by -- system class loader NULL
System.out.println(Object.class.getClassLoader());
// How to get the path of the loaded classes in the system classloader
System.out.println(System.getProperty("java.class.path"));
* E:\JDK\jre\lib\charsets.jar; * E:\ Java \jre\lib\charsets. * E:\JDK\jre\lib\deploy.jar; * E:\JDK\jre\lib\ext\access-bridge-64.jar; * E:\JDK\jre\lib\ext\cldrdata.jar; * E:\JDK\jre\lib\ext\dnsns.jar; * E:\JDK\jre\lib\ext\jaccess.jar; * E:\JDK\jre\lib\ext\jfxrt.jar; * E:\JDK\jre\lib\ext\localedata.jar; * E:\JDK\jre\lib\ext\nashorn * .jar; E:\JDK\jre\lib\ext\sunec.jar; * E:\JDK\jre\lib\ext\sunjce_provider.jar; * E:\JDK\jre\lib\ext\sunmscapi.jar; * E:\JDK\jre\lib\ext\sunpkcs11 * .jar; E:\JDK\jre\lib\ext\zipfs.jar; * E:\JDK\jre\lib\javaws.jar; * E:\JDK\jre\lib\jce.jar; * E:\JDK\jre\lib\jfr.jar; * E:\JDK\jre\lib\jfxswt.jar; * E:\JDK\jre\lib\jsse.jar; * E:\JDK\jre\lib\management-agent.jar; * E:\JDK\jre\lib\plugin.jar; * E:\JDK\jre\lib\resources.jar; * E:\JDK\jre\lib\rt.jar; * F: cloud \Code\JavaSE\out\production\ basic syntax; * F:\ cloud \Code\JavaSE\ Basic syntax \ SRC \com\lib\commons-io-2.6.jar; * D: IntelliJ IDEA 2018.2.4\lib\idea_rt.jar * */}}Copy the code
Parent delegation mechanism
- Prevent reloading the same
.class
. You can ask the delegate up there, so once it’s loaded, you don’t have to load it again. Ensure data security. - Ensure that the core
.class
Can’t be tampered with. By delegating, you don’t tamper with the core.class
, even if tampered with will not load, even if loaded will not be the same.class
The object. Different loaders load the same.class
It’s not the sameClass
Object. That’s guaranteedClass
Perform security.
operation
-
Gets the parent class and implemented interface
Class cls = Class.forName("package.Student"); Class parent = cls.getSuperClass();// System.out.println(cls.getName()); Class[] infas = cls.getInterfaces();// for(Class c : infas){ System.out.println(c.getName()); } Copy the code
-
Get constructor
import java.lang.reflection.Constructor; Constructor[] cons1 = cls.getConstructors();// Only public constructors are returned Constructor[] cons2 = cls.getDeclaredConstructors();// Return all (public + private) constructors for(Constructor c : cons2){ System.out.println(c.getName());// Return the constructor name System.out.println(c.getModifiers());// Returns the constructor modifier type int //1 is public and 2 is private Class params = c.getParameterTypes();// Get the constructor parameter type for(Class p in params){ System.out.println(p.getName()); }}Copy the code
-
Create objects through reflection
Student stu = (Student)cls.newInstance();// this is equivalent to calling the no-argument common construct of the Student class Constructor c = cls.getConstructor(String.class);// Get a public construct of type String for the Student class argument Student stu2 = c.newInstance(); // Private constructs can be forced to be called through reflection Constructor c2 = cls.getDeclaredConstructor(String.class,int.class); // Get a private construct of the Student class whose arguments are of type String and int c2.setAccessible(true);// Must be called to remove private encapsulation Student stu3 = c2.newInstance(); Copy the code
-
Access method
import import java.lang.reflection.Method; Method[] ms = cls.getMethods();// Get all the public methods of the class Method[] ms = cls.getDeclaredMethods();// Get all the methods of the class for(Method m : ms){ System.out.println(m.getName());/ / the method name System.out.println(m.getReturnType());// Return value type System.out.println(m.getModifiers());// return modifier Class[] params = m.getParameterTypes(); if(params ! =null && params.length > 0) {for(Class p in params){ System.out.println(p.getName()); }}}Copy the code
-
Retrieve attributes
import import java.lang.reflection.Field; Field[] fs = cls.getFields();// return public Field[] fs = cls.getDeclaredFields();// Return all for(Field f : fs){ System.out.println(f.getType());// Returns the attribute type // returns the same modifier and property name as the previous method } Copy the code
-
Gets the package in which the class resides
import import java.lang.Package; Package pg = cls.getPackage(); System.out.println(pg.getName()); Copy the code
-
Calling the specified method
Method m = cls.getMethod("setInfo",String.class,String.class); // Get a public method called setInfo with an argument (String,String) m.invoke(obj,"asd"."das"); //obj is an instance of the method that needs to be called. You can use the object created by reflection earlier // To call a private method, just change getMethod to getDeclaredMethod and unwrap m.setAccessible(true) // Call a method with a return value String str = (String)m.invoke(); Copy the code
-
Invoking specified properties
Field f = cls.getField("school");// Or attribute school f.set(stu,No. 1 Middle School);// Set the school property to the stu object String school = (String)f.get(stu); // To call a private method, simply change getField to getDeclaredField and unwrap m.setAccessible(true) Copy the code
Java memory analysis
PS: The method area is a special heap.
Class loading and the understanding of ClassLoader
- Load: Load the bytecode content of the class file into memory, convert this static data into a runtime data structure for the method area, and generate a java.lang.class object that represents this class
- Linking: The process of merging the binaries of Java classes into the JVM’s running state
- Validation: To ensure that the loaded class information complies with the JVM specification and that there are no security issues
- Preparation: The stage of formally allocating memory for class variables (static) and setting default initial values for class variables, which will be allocated in the method area
- Resolution: The process of replacing symbolic references (constant names) in the virtual machine constant pool with direct references (addresses)
- Initialization:
- Execute the class constructor
<clinit>()
The process of a method. Class constructor<clinit>()
Methods are generated by combining the assignment actions of all class variables in a class that the compiler automatically collects with statements in a static code block. (Class constructors build class information, not objects of that class.) - When initializing a class, if the parent class is not initialized, the initialization of the parent class must be triggered first
- The virtual machine guarantees a class of
<clinit>()
Methods are locked and synchronized correctly in a multithreaded environment
- Execute the class constructor
When does class initialization occur
- Active reference to a class (class initialization must occur)
- When the virtual machine starts, initialize the class in which the main method resides
- Instantiate an object of a class
- Call static members of the class (except final constants) and static methods
- Make a reflection call to the class using the methods of the java.lang.Reflect package
- When initializing a class, if its parent class is not initialized, its parent class is initialized first
- A passive reference to a class (class initialization does not occur)
- When accessing a static field, only classes that actually declare the field are initialized. For example, when a static variable of a parent class is referred to by a subclass, it does not cause the subclass to be initialized
- Defining a class reference through an array does not trigger initialization of the class
- Referencing constants does not trigger initialization of this class (constants are stored in the calling class’s constant pool during the linking phase)
package com.volcano.reflection;
// When does class initialization take place and all tests must be opened independently except for the first comment, otherwise it is not accurate
public class TestReflection3 {
static {
//1. The virtual machine starts and initializes the main class first
System.out.println("Main method loaded");
}
public static void main(String[] args) throws ClassNotFoundException {
//2. Instantiating an object does
//new Father();
//3. Calling static members of the class (except final constants) and static methods will
//System.out.println(Son.a);
//4. Make a reflection call to a class using the java.lang.reflect package's methods
//Class cls = Class.forName("com.volcano.reflection.Father");
//5. When initializing a class, if its parent class is not initialized, its parent class is initialized first
//new Son();
//6. When accessing a static field, only classes that actually declare the field are initialized
//System.out.println(Father.a); // only load Father
//System.out.println(Son.a); // Because a is a static member of Father
//7. Class references defined through arrays will not trigger initialization of this class
//Father[] fathers = new Father[10];
//8. Referencing constants does not trigger initialization of this class
//System.out.println(Father.B);}}class Father{
static {
System.out.println("Father is loaded");
}
static int a=100;
static final int B = 300;
}
class Son extends Father{
static {
System.out.println("Son is loaded");
}
static int c=200;
}
Copy the code
Research and Application
The main reflection related apis:
java.lang.class
: represents a classjava.lang.reflect.Method
: represents the method of the classjava.lang.reflect.Field
: represents a member variable of the classjava.lang.reflect.Constructor
: represents the constructor of the class
package com.volcano.reflection;
public class TestReflection1 {
public static void main(String[] args) throws ClassNotFoundException {
// Get the Class object by reflection, throw an exception
Class cla = Class.forName("com.volcano.reflection.User");
Class clb = Class.forName("com.volcano.reflection.User");
Class clc = Class.forName("com.volcano.reflection.User");
// The same hash value indicates that a Class has only one Class object
// After a Class is loaded, the entire structure of the Class is encapsulated in a Class objectSystem.out.println(cla.hashCode()); System.out.println(clb.hashCode()); System.out.println(clc.hashCode()); }}// Entity class
class User{
private int id;
private String name;
private int age;
public User(a) {}public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId(a) {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge(a) {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString(a) {
return "User{" +
"id=" + id +
", name='" + name + '\' ' +
", age=" + age +
'} '; }}Copy the code
356573597
356573597
356573597
Copy the code
application
We can get the Class object of a Class:
-
Create an object of the Class through the newInstance() method of the Class object
- Condition 1: The class must have a no-parameter constructor
- Condition 2: Class constructor access is sufficient
- Without the parameterless constructor:
- By Class
getDeclaredConstructor(Class ... parameterTypes)
Gets the constructor for the specified parameter of this class - Pass an array of objects to the constructor parameters that contain the parameters required by the constructor
- Instantiate objects by Constructor
- By Class
package com.volcano.reflection; import java.lang.reflect.InvocationTargetException; public class TestReflection5 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { // Get the Class object. The User source for this example is above Class aClass = Class.forName("com.volcano.reflection.User"); Instantiate an object, essentially calling the no-argument constructor User user = (User) aClass.newInstance(); System.out.println(user); // If no parameterless constructor is available, or if a parameterless constructor is required User user2 = (User) aClass.getConstructor(int.class,String.class,int.class).newInstance(1."a".2); System.out.println(user2); }}Copy the code
User{id=0, name='null', age=0} User{id=1, name='a', age=2} Copy the code
-
Get methods and properties by reflection and use them
package com.volcano.reflection; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestReflection6 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException { Class aClass = Class.forName("com.volcano.reflection.User"); User user = (User) aClass.newInstance(); // Specify the method name and the parameter fetching method Method setName = aClass.getMethod("setName", String.class); //invoke(object, method parameter), whether or not it returns a value depends on the method retrieved by reflection setName.invoke(user,"candashuai"); System.out.println(user.getName()); User user2 = (User) aClass.newInstance(); // Get the name attribute Field name = aClass.getDeclaredField("name"); // The name property is private, modifying it directly will report an error, and the method will operate before invoke if it is private //setAccessible(true) Turns off security monitoring for the program name.setAccessible(true); name.set(user2,"volcano"); System.out.println(user2.getName()); }}Copy the code
candashuai volcano Copy the code
-
setAccessible(boolean)
- Method, Field, Constructor objects are available
setAccessible()
methods setAccessible()
Enables or disables access security check- Parameter values for
true
Means that reflected objects should be used without Java language access checks.- Improve the efficiency of reflection. If reflection must be used in code that needs to be called frequently, set it to
true
- Make private members that would otherwise not be accessible accessible
- Improve the efficiency of reflection. If reflection must be used in code that needs to be called frequently, set it to
- Parameter values for
false
Indicates that reflected objects should implement Java language access checks
- Method, Field, Constructor objects are available
-
Reflection operation generics (== completely ignorant of ==)
- Java introduced generics by using the mechanism of generic erasure. Generics in Java are only used by the compiler Javac to ensure data security and avoid casting problems. However, once compilation is complete, all types related to generics are erased
- To manipulate these types through reflection, Java has added a new one
ParameterizedType
.GenericArrayType
.TypeVariable
andWildcardType
Several types to represent types that cannot be generalized into a Class but are named the same as the original typeParameterizedType
: represents a parameterized type, such asCollection<String>
GenericArrayType
: represents an array type whose element type is a parameterized type or type variableTypeVariable
: is the common parent interface for variables of various typesWildcardType
: represents a wildcard type expression
-
Reflection gets annotation information
package com.volcano.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class TestReflection7 {
// Declare generic parameter methods
public void test1(Map<String,Integer> map, List<User> users){
System.out.println("...");
}
public List<String> test2(a){
return null;
}
// Declare the generic return value method
public static void main(String[] args) throws NoSuchMethodException {
Class cls = TestReflection7.class;
Method test1 = cls.getMethod("test1", Map.class, List.class);
Type[] genericParameterTypes = test1.getGenericParameterTypes();
for (Type type:genericParameterTypes){
System.out.println("-"+type);
if(type instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
for(Type actualTypeArgument :actualTypeArguments){
System.out.println(actualTypeArgument);
}
}
}
Method test2 = cls.getMethod("test2");
Type returnType = test2.getReturnType();
System.out.println("-"+returnType);
if(returnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
for(Type actualTypeArgument :actualTypeArguments){ System.out.println(actualTypeArgument); }}}}Copy the code
-java.util.Map<java.lang.String, java.lang.Integer>
class java.lang.String
class java.lang.Integer
-java.util.List<com.volcano.reflection.User>
class com.volcano.reflection.User
-interface java.util.List
Copy the code
A dynamic proxy
Problem: Suppose you have 100 Java classes with 10 methods each in a project, and you need to add two lines of code to each method to print the start and end of the execution of the current method.
Manual modification is definitely not appropriate, so you need a dynamic proxy class.
public interface ITest{
void test1(a);
void test2(a);
}
Copy the code
public class Test implements ITest{
@Override
public test1(a){
System.out.println("test1.... ing...");
}
public test1(a){
System.out.println("test2.... ing..."); }}Copy the code
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo implements InvocationHandler{
Object obj;// The proxied object
// Note: if an object wants to be proxied via proxy. newProxyInstance,
// The class of this object must have the corresponding interface
Class Test implements the ITest interface
public ProxyDemo(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println(method.getName()+"Execution begins");
Object result = method.invoke(this.obj, args);// Executes the method that specifies the proxy object
return result;
System.out.println(method.getName()+"End of execution"); }}Copy the code
/ / use
ITest test = new Test();// The polymorphic representation
InvocationHandler handler = new ProxyDemo(test);//ProxyDemo implements InvocationHandler
/ * Proxy newProxyInstance (this, interfaces, obj) parameter 1:2: the Proxy objects of this parameter is a Proxy object interfaces parameters of 3: the return value is a Proxy object itself: Object returns the successfully proxied Object cast as appropriate, in this case test */
Test t = (Test)Proxy.newProxyInstance(handler.getClass().getClassLoader(), test.getClass().getInterfaces(), handler);
t.test1();
t.test2();// Both methods have output statements that start and end execution
Copy the code