Getting started with the Reflect class

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));
	}
}

Keywords: Java Spring JavaSE intellij-idea

Added by clodagh2000 on Mon, 29 Nov 2021 06:56:40 +0200