Chapter 16 reflection
16.1 class loading
Class life cycle in memory: load – > use – > unload
16.1.1 loading process of class
When a program actively uses a class, if the class has not been loaded into memory, the system will initialize the class through three steps: loading, connecting and initialization. If there is no accident, the JVM will complete these three steps continuously. Therefore, sometimes these three steps are collectively referred to as class loading.
Class loading is divided into three stages:
(1) Loading: load
It refers to reading clas bytecode data of type into memory
(2) Connection: link
① Verification: verify the legitimacy, etc
② Preparation: prepare the corresponding memory (method area), create Class objects, assign default values to Class variables, and assign initial values to static constants.
③ Parsing: replace the symbol reference in bytecode with the corresponding direct address reference
(3) Initialization: initialize means to execute the class initialization method. In most cases, class initialization is completed after class loading. In some cases, class initialization will be delayed.
16.1.2 class initialization
1. What actions will cause class initialization?
(1) To run the class where the main method is located, first complete the class initialization, and then execute the main method
(2) The first time you use a type is when you new its object. If the class is not initialized at this time, complete class initialization first and then instance initialization
(3) Call the static members (class variables and class methods) of a class. If the class is not initialized, complete the class initialization first
(4) When initializing a subclass, if it is found that its parent class has not been initialized, initialize the parent class first
(5) When a class is operated through reflection, if the class is not initialized, it will also cause the class to initialize first
Class initialization executes () which consists of (1) the explicit assignment code of class variables and (2) the code in the static code block
class Father{ static{ System.out.println("main The parent class of the class in which the method is located(1)");//When a child class is initialized, the parent class is initialized } } public class TestClinit1 extends Father{ static{ System.out.println("main The class in which the method resides(2)");//The class of the main method is initialized } public static void main(String[] args) throws ClassNotFoundException { new A();//The first time you use a is to create its object, which initializes class A B.test();//Using static members of class B directly initializes class B Class clazz = Class.forName("com.atguigu.test02.C");//Class C is initialized by reflection operation } } class A{ static{ System.out.println("A Class initialization"); } } class B{ static{ System.out.println("B Class initialization"); } public static void test(){ System.out.println("B Class"); } } class C{ static{ System.out.println("C Class initialization"); } }
2. What uses class operations but does not cause class initialization?
(1) Use a static constant of a class (static final)
(2) Calling static variables and methods of the parent class through a subclass will only lead to the initialization of the parent class, not the subclass, that is, only the class declaring static members will be initialized
(3) Declaring an array with a type and creating an array object does not cause this class to initialize
public class TestClinit2 { public static void main(String[] args) { System.out.println(D.NUM);//Class D is not initialized because NUM is final System.out.println(F.num); F.test();//Class F will not initialize, class E will initialize, because num and test() are declared in class E //Class G will not be initialized, and there is no formal class G at this time G[] arr = new G[5];//Instead of creating an object of G, an array object is created to hold the G object //G [] is a new type. It is a new type generated by dynamic compilation of array classes //G[].class } } class D{ public static final int NUM = 10; static{ System.out.println("D Class initialization"); } } class E{ static int num = 10; static{ System.out.println("E Initialization of parent class"); } public static void test(){ System.out.println("Static method of parent class"); } } class F extends E{ static{ System.out.println("F Initialization of subclasses"); } } class G{ static{ System.out.println("G Class initialization"); } }
16.1.3 class loader
Many developers have encountered java.lang.ClassNotFoundException or java.lang.NoClassDefError. To better solve these problems, or in some special application scenarios, such as supporting dynamic loading of classes or encrypting and decrypting compiled bytecode files, you need to customize the class loader, Therefore, understanding the class loader and its class loading mechanism has become one of the necessary skills of every Java developer.
1. Class loaders are divided into:
(1) Bootstrap Classloader is also called root classloader
It is responsible for loading jre/rt.jar Core library It is not itself Java Code implementation, nor is it ClassLoader Subclass of, which is often returned when getting its object null
(2) Extension ClassLoader
It is responsible for loading jre/lib/ext expanded memory bank It is ClassLoader Subclass of
This is the extension class loader. It's written incorrectly as tomcat
(3) Application Classloader
It is responsible for loading the project classpath Class under path It is ClassLoader Subclass of
(4) Custom class loader
When your program needs to load classes in the "specific" directory, you can customize the class loader; When the bytecode file of your program needs to be encrypted, a custom class loader is often provided to decode it The custom class loader you will see later: tomcat in
2. Parent delegation mode of class loader in Java System
Brief description:
If the class loader at the next level receives a task, it will first search whether it has been loaded. If not, it will upload the task first. If it has not been loaded, it will go all the way to the root loader. If the root loader is not found under its responsible path, it will return. If it is not found all the way back to the last level, it will report ClassNotFoundException or NoClassDefError,If it is found at a certain level, it returns directly Class Object.
The application class loader regards the extension class loader as the parent loader,
The extension class loader treats the boot class loader as the parent loader.
It is not an inheritance relationship, but a combination.
Application class loader ----- > extension class loader ----- -- > guide the class loader to upload. If it cannot be found, it will be sent back
Application class loader < ---- extension class loader < ---- boot class loader
No more errors found
**What is a combination** One class acts as an attribute of another class
16.2 javalang.Class class
Java reflection mechanism is to know all the properties and methods of any class in the running state; For any object, you can call any of its methods and properties; This kind of dynamically obtained information and the function of dynamically calling object methods are called the reflection mechanism of Java language.
To dissect a Class, you must first obtain the Class object of the Class. To analyze a Class or solve a specific problem with reflection is to use the relevant API (1) java.lang.Class (2) java.lang.reflect. *. Therefore, the Class object is the root of reflection.
1. What types can get Class objects
All Java types
Use code example
//(1) Basic data type and void For example: int.class void.class //(2) Classes and interfaces For example: String.class Comparable.class //(3) Enumeration For example: ElementType.class //(4) Annotation For example: Override.class //(5) Array For example: int[].class
2. Four ways to get Class objects
(1) Type name.class
Requires a type known during compilation
(2) Object. getClass()
Gets the runtime type of the object
(3) Class. Forname (full name of type)
Can get types unknown during compilation
(4) ClassLoader's ClassLoader object. Loadclass (type full name)
You can use the system class load object or custom loader object to load the type under the specified path
public class TestClass { @Test public void test05() throws ClassNotFoundException{ Class c = TestClass.class; ClassLoader loader = c.getClassLoader(); Class c2 = loader.loadClass("com.atguigu.test05.Employee"); Class c3 = Employee.class; System.out.println(c2 == c3); } @Test public void test03() throws ClassNotFoundException{ Class c2 = String.class; Class c1 = "".getClass(); Class c3 = Class.forName("java.lang.String"); System.out.println(c1 == c2); System.out.println(c1 == c3); } }
3. View the classloader object of a class
//Gets the application class loader object //Gets the extension class loader object //Get root loader object
16.3 application of reflection
16.3.1 get type details
You can obtain: package, modifier, type name, parent class (including generic parent class), parent interface (including generic parent interface), member (property, constructor, method), annotation (on class, method, property)
Sample code for general information:
public class TestClassInfo { public static void main(String[] args) throws NoSuchFieldException, SecurityException { //1. Get a Class object of a certain type first Class clazz = String.class; //A metaphor clazz is like a shadow in a mirror //2. Get class information //(1) Get the Package object, that is, all java packages are Package objects Package pkg = clazz.getPackage(); System.out.println("Package name:" + pkg.getName()); //(2) Get modifier //In fact, the Modifier is Modifier, which has many constant values /* * 0x It's hexadecimal * PUBLIC = 0x00000001; 1 1 * PRIVATE = 0x00000002; 2 10 * PROTECTED = 0x00000004; 4 100 * STATIC = 0x00000008; 8 1000 * FINAL = 0x00000010; 16 10000 * ... * * The design idea is to use a bit of binary as 1 to represent a modifier. Only one bit of the whole binary is 1 and the rest are 0 * * mod = 17 0x00000011 * if ((mod & PUBLIC) != 0) Description modifier has public * if ((mod & FINAL) != 0) Description modifier has final */ int mod = clazz.getModifiers(); System.out.println(Modifier.toString(mod)); //(3) Type name String name = clazz.getName(); System.out.println(name); //(4) The parent Class also has the Class object corresponding to the parent Class Class superclass = clazz.getSuperclass(); System.out.println(superclass); //(5) Parent interfaces Class[] interfaces = clazz.getInterfaces(); for (Class class1 : interfaces) { System.out.println(class1); } //(6) Class, a property you declare, which is the object of Field /* Field clazz.getField(name) Get a property object according to the property name, but you can only get public Field[] clazz.getFields(); Get all public properties Field clazz.getDeclaredField(name) Get a property object according to the property name to get the declared Field[] clazz.getDeclaredFields() Get all declared properties */ Field valueField = clazz.getDeclaredField("value"); // System.out.println("valueField = " +valueField); Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { //Modifier, data type, property name int modifiers = field.getModifiers(); System.out.println("Modifier for property:" + Modifier.toString(modifiers)); String name2 = field.getName(); System.out.println("Property name:" + name2); Class<?> type = field.getType(); System.out.println("Data type of property:" + type); } System.out.println("-------------------------"); //(7) Constructors Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor constructor : constructors) { //Modifier, constructor name, constructor parameter list, thrown exception list int modifiers = constructor.getModifiers(); System.out.println("Modifier for constructor:" + Modifier.toString(modifiers)); String name2 = constructor.getName(); System.out.println("Constructor Name:" + name2); //parameter list System.out.println("Formal parameter list:"); Class[] parameterTypes = constructor.getParameterTypes(); for (Class parameterType : parameterTypes) { System.out.println(parameterType); } //Exception list System.out.println("Exception list:"); Class<?>[] exceptionTypes = constructor.getExceptionTypes(); for (Class<?> exceptionType : exceptionTypes) { System.out.println(exceptionType); } } System.out.println("=--------------------------------"); //(8) Methods Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method method : declaredMethods) { //Modifier, return value type, method name, parameter list, exception list int modifiers = method.getModifiers(); System.out.println("Modifier for method:" + Modifier.toString(modifiers)); Class<?> returnType = method.getReturnType(); System.out.println("return type:" + returnType); String name2 = method.getName(); System.out.println("Method name:" + name2); //parameter list System.out.println("Formal parameter list:"); Class[] parameterTypes = method.getParameterTypes(); for (Class parameterType : parameterTypes) { System.out.println(parameterType); } //Exception list System.out.println("Exception list:"); Class<?>[] exceptionTypes = method.getExceptionTypes(); for (Class<?> exceptionType : exceptionTypes) { System.out.println(exceptionType); } } } }
16.3.2 create objects of any reference type
There are two ways:
1. Instantiate directly through Class object (parameter free construction is required)
2. Instantiate by getting the constructor object
Steps of mode 1:
(1) Get the Class object of this type (2) and create the object
@Test public void test2()throws Exception{ Class<?> clazz = Class.forName("com.atguigu.test.Student"); //Caused by: java.lang.NoSuchMethodException: com.atguigu.test.Student.<init>() //That is, if the Student does not have a parameterless structure, there is no parameterless instance initialization method < init > Object stu = clazz.newInstance(); System.out.println(stu); } @Test public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ // AtGuigu obj = new AtGuigu();// Cannot be created during compilation Class<?> clazz = Class.forName("com.atguigu.test.AtGuigu"); //clazz stands for com.atguigu.test.AtGuigu type //clazz.newInstance() creates the object of AtGuigu Object obj = clazz.newInstance(); System.out.println(obj); }
Steps of mode 2:
(1) Get Class object of this type (2) get constructor object (3) create object
setAccessible(true) can also be called if the scope modified by the constructor's permission modifier is not visible
Example code:
public class TestNewInstance { @Test public void test3()throws Exception{ //(1) Get Class object Class<?> clazz = Class.forName("com.atguigu.test.Student"); /* * Gets the parameterized construct in the Student type * If there are multiple constructors, we usually obtain the specified constructor according to the formal parameter [type] list * For example: public Student(int id, String name) */ //(2) Get constructor object Constructor<?> constructor = clazz.getDeclaredConstructor(int.class,String.class); //(3) Create instance object // T newInstance(Object... initargs) this Object... Is a list of arguments constructed with parameters when creating an Object Object obj = constructor.newInstance(2,"Zhang San"); System.out.println(obj); } }
16.3.3 operation of any type of attribute
(1) Gets the Class object of this type
Class clazz = Class.forName("com.atguigu.bean.User");
(2) Get property object
Field field = clazz.getDeclaredField("username");
(3) Set properties accessible
field.setAccessible(true);
(4) Create instance object: if the operation is a non static property, you need to create an instance object
Object obj = clazz.newInstance();
(4) Set attribute value
field.set(obj,"chai");
(5) Get property value
Object value = field.get(obj);
If you operate on static variables, the instance object can be omitted and represented by null
Example code:
public class TestField { public static void main(String[] args)throws Exception { //1. Gets the Class object of the Student Class clazz = Class.forName("com.atguigu.test.Student"); //2. Get the attribute object, for example: id attribute Field idField = clazz.getDeclaredField("id"); //3. If the id is private and access is not accessible in the current class, we need to do the following idField.setAccessible(true); //4. Create an instance object, that is, create a Student object Object stu = clazz.newInstance(); //5. Get property value /* * Previously: int variable = Student object. getId() * Now: Object id attribute object. Get (Student object) */ Object value = idField.get(stu); System.out.println("id = "+ value); //6. Set attribute value /* * Previous: Student object. Setid (value) * Now: id attribute object. Set (Student object, value) */ idField.set(stu, 2); value = idField.get(stu); System.out.println("id = "+ value); } }
16.3.4 calling any type of method
(1) Gets the Class object of this type
Class clazz = Class.forName("com.atguigu.service.UserService");
(2) Get method object
Method method = clazz.getDeclaredMethod("login",String.class,String.class);
(3) Create instance object
Object obj = clazz.newInstance();
(4) Call method
Object result = method.invoke(obj,"chai","123);
If the scope modified by the permission modifier of the method is not visible, setAccessible(true) can also be called
If the method is static, the instance object can also be omitted and replaced with null
Example code:
public class TestMethod { @Test public void test()throws Exception { // 1. Gets the Class object of the Student Class<?> clazz = Class.forName("com.atguigu.test.Student"); //2. Get method object /* * To uniquely locate a method in a class, you need: (1) method name (2) formal parameter list, because the method may be overloaded * * For example: void setName(String name) */ Method method = clazz.getDeclaredMethod("setName", String.class); //3. Create instance object Object stu = clazz.newInstance(); //4. Call method /* * Previous: Student object. Setname (value) * Now: method object. Invoke (Student object, value) */ method.invoke(stu, "Zhang San"); System.out.println(stu); } }
16.3.5 get generic parent class information
Sample code to get generic parent class information:
/* Type: * (1)Class * (2)ParameterizedType * For example: father < string, integer > * ArrayList<String> * (3)TypeVariable * For example: T, U,E,K,V * (4)WildcardType * For example: * ArrayList<?> * ArrayList<? super Lower limit > * ArrayList<? extends Upper limit > * (5)GenericArrayType * For example: T [] * */ public class TestGeneric { public static void main(String[] args) { //Requirement: at runtime, get the generic argument < string, integer > of the generic parent class of Son type //(1) Or get the Class object first Class clazz = Son.class;//Any of the four forms is OK //(2) Get generic parent class // Class sc = clazz.getSuperclass(); // System.out.println(sc); /* * getSuperclass()Only the parent class name can be obtained, and the generic argument list of the parent class cannot be obtained */ Type type = clazz.getGenericSuperclass(); // Father < string, integer > belongs to ParameterizedType ParameterizedType pt = (ParameterizedType) type; //(3) Gets the list of generic arguments for the generic parent class Type[] typeArray = pt.getActualTypeArguments(); for (Type type2 : typeArray) { System.out.println(type2); } } } //Generic parameter: < T, u > class Father<T,U>{ } //Generic argument: < string, integer > class Son extends Father<String,Integer>{ }
16.3.6 reading annotation information
Example code reads annotation information:
public class TestAnnotation { public static void main(String[] args) { //Requirement: you can obtain the value of @ MyAnnotation configured above MyClass type //Read annotation // (1) Get Class object Class<MyClass> clazz = MyClass.class; //(2) Get annotation object //Gets the specified annotation object MyAnnotation my = clazz.getAnnotation(MyAnnotation.class); //(3) Get configuration parameter value String value = my.value(); System.out.println(value); } } //statement @Retention(RetentionPolicy.RUNTIME) //Note that this annotation can be retained until runtime @Target(ElementType.TYPE) //Note: this annotation can only be used on types, including classes, interfaces, enumerations, etc @interface MyAnnotation{ //Configuration parameter. If there is only one configuration parameter and the name is value, value can be omitted during assignment= String value(); } //Using annotations @MyAnnotation("/login") class MyClass{ }
16.3.7 obtaining internal or external information
public Class<?> [] getclasses(): returns all public internal classes and internal interfaces. Includes public class and interface members inherited from a superclass and public class and interface members declared by the class.
public Class<?> [] getdeclaraedclasses(): returns an array of class objects that reflect all classes and interfaces declared as members of the class represented by this class object. It includes public, protected, default (package) access and private classes and interfaces declared by this class, but does not include inherited classes and interfaces.
public Class<?> Getdeclarangclass(): if the class or interface represented by this class object is an internal class or internal interface, its external class or external interface will be returned; otherwise, null will be returned.
@Test public void test5(){ Class<?> clazz = Map.class; Class<?>[] inners = clazz.getDeclaredClasses(); for (Class<?> inner : inners) { System.out.println(inner); } Class<?> ec = Map.Entry.class; Class<?> outer = ec.getDeclaringClass(); System.out.println(outer); }
16.3.8 dynamically create and operate arrays of any type
An Array class is also provided under the java.lang.reflect package. The Array object can represent all arrays. The program can dynamically create arrays and operate Array elements by using the Array class.
The Array class provides the following methods:
Public static object newinstance (class <? > componenttype, int... dimensions): creates a new array with the specified component type and dimension.
public static void setXxx(Object array,int index,xxx value): modify the value of the [index] element in the array to value. Xxx here corresponds to 8 basic data types. If the type of this attribute is a reference data type, the set(Object array,int index, Object value) method is directly used.
public static xxx getXxx(Object array,int index,xxx value): returns the value of the [index] element in the array. Xxx here corresponds to 8 basic data types. If the type of this attribute is a reference data type, you can directly use the get(Object array,int index) method.
import java.lang.reflect.Array; public class TestArray { public static void main(String[] args) { Object arr = Array.newInstance(String.class, 5); Array.set(arr, 0, "Shang Silicon Valley"); Array.set(arr, 1, "Tong Gang"); System.out.println(Array.get(arr, 0)); System.out.println(Array.get(arr, 1)); System.out.println(Array.get(arr, 2)); } }
dimensions): creates a new array with the specified component type and dimension.
public static void setXxx(Object array,int index,xxx value): modify the value of the [index] element in the array to value. Xxx here corresponds to 8 basic data types. If the type of this attribute is a reference data type, the set(Object array,int index, Object value) method is directly used.
public static xxx getXxx(Object array,int index,xxx value): returns the value of the [index] element in the array. Xxx here corresponds to 8 basic data types. If the type of this attribute is a reference data type, you can directly use the get(Object array,int index) method.
import java.lang.reflect.Array; public class TestArray { public static void main(String[] args) { Object arr = Array.newInstance(String.class, 5); Array.set(arr, 0, "Shang Silicon Valley"); Array.set(arr, 1, "Tong Gang"); System.out.println(Array.get(arr, 0)); System.out.println(Array.get(arr, 1)); System.out.println(Array.get(arr, 2)); } }