Reflection as an advanced feature of Java, many frameworks have used the knowledge of reflection, such as Spring, Hibernate, etc., through configuration can dynamically interfere with the operation of the program, so what is reflection?

To understand Java reflection, first understand the loading process of the class, such as this line of code Person p = new Person(); We want to create a Person object and use p as a reference to the object. In the Java virtual machine, class loading is performed before object generation (memory allocation) is performed. During class loading, the class loader is responsible for adding the class’s compiled class (bytecode) file to memory and creating a class object, which is an instance of the class. That is, the above line of code looks like it’s just creating a Person object, but it will also create a class object if the class is used for the first time, before the class loader has loaded the class file into memory.

In Java, everything is an object. Class is an abstraction of a Class of objects. Class is a concept, and Class itself is also a kind of object. In Java, they are the objects of Class Class. These classes are all reflection related and can be found in the java.lang.Reflect package.

How can we interfere with what the program is doing at runtime? Such as creating a class that cannot be determined at compile time.

We can do this with reflection, which takes information about itself at runtime, such as information about a class, and dynamically creates objects for that class. The problem is that a class is not known at compile time, but only at run time. Class. ForName (” com.mysql.jdbc.driver “); If one day we want to switch to an Oracle database, you might change the parameter in the forName() method to the Oracle database driver name. But we can do this without modifying the code. Like most frameworks, we can write a configuration file, and the parameters in the forName() method are read dynamically in the configuration file, leaving the compiled code untouched. This is really an application of reflection. In addition, when we write code, we type a. After the object, the IDE (such as Eclipse) will automatically list the methods of the object. In this case, the IDE uses reflection to find the corresponding Class object from the object, so that we can find the properties and methods in the Class.

There are three ways to get a Class object

From the introduction above, you can see that this Class object is the key to our use of reflection, and there are three ways to get this object.

ForName () public static Class<? > forName(String className)

Class.forName("Person")
Copy the code

This method is used in JDBC above.

2. Call the hidden class attribute of the class.

Person.class
Copy the code

Public final Native Class<? > getClass()

Person p = new Person();
p.getClass();
Copy the code

All classes inherit directly or indirectly from Object, whether explicitly declared or not.

The second method of obtaining Class objects is recommended because the existence of the Class is checked at compile time, which is safer, and because there are no method calls and properties are used, performance is higher.

2. Methods in Class objects

So we’ve got the Class object, so we’ve got all the information about that Class. Think about what information is in the class we wrote? Such as the following class

If we get the Class object, we get everything about the object, including constructors, properties, methods, annotations.

1. Methods to obtain attributes

public Field getField(String name)
public Field[] getFields()
public Field getDeclaredField(String name)
public Field[] getDeclaredFields()
Copy the code

Name is the name of the attribute

2. The method to get the constructor

public Constructor<T> getConstructor(Class<? >... parameterTypes) public Constructor<? >[] getConstructors() public Constructor<T> getDeclaredConstructor(Class<? >... parameterTypes) public Constructor<? >[] getDeclaredConstructors()Copy the code

Constructors also have the Java equivalent Class Constructor, parameterTypes as a Class object, which is a mutable argument.

3. Methods of obtaining ordinary functions

public Method getMethod(String name, Class<? >... parameterTypes) public Method[] getMethods() public Method getDeclaredMethod(String name, Class<? >... parameterTypes) public Method[] getDeclaredMethods()Copy the code

Name is the name of the method and parameterTypes is the Class object of the parameter, which is a mutable parameter.

4. Method of obtaining annotations

public boolean isAnnotation()
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
public Annotation[] getAnnotations()
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
public Annotation[] getDeclaredAnnotations()
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass)
public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass)
Copy the code

AnnotationClass is the corresponding annotationClass.

5. Other common methods

Public String getName() // Returns the full pathname String of the type (Class, interface, array, or primitive type) represented by the Class object public T newInstance() // This method is Java instanceof Public ClassLoader getClassLoader() public Class<? Super T> getSuperclass() // Returns the Class of the superclass representing the entity (Class, interface, primitive type, or void) represented by this Class public Boolean isArray() // If Class Object represents an array and returns true, Public Boolean isInterface() // Check whether the specified Class object represents an interface type public Boolean isPrimitive() // Check whether the specified Class object represents an interface type Basic Java typesCopy the code

Here is the test code:

Animal class

public class Animal { public String name; protected String sex; private int age; Public Animal() {} public void run() {system.out.println (" Animal is running "); }}Copy the code

Dog class

public class Dog extends Animal{ public String color; protected String heart; private String unknown; public Dog() { } private Dog(String color) { this.color = color; } @Override public void run() { super.run(); System.out.println(" The dog is running "); } void test() {system.out.println ("test method "); } private void fanzhi() {system.out.println (); }}Copy the code

AnimalTest class

import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; Public class AnimalTest {@test // constructorTest() throws NoSuchMethodException {class dog = Dog.class; System.out.println(" Get the specified public constructor "); System.out.println(dog.getConstructor(String.class)); System.out.println(" Get all public constructors "); Constructor[] constructors1 = dog.getConstructors(); for(Constructor constructor : constructors1) { System.out.println(constructor); } system.out.println (" Get the specified constructor, unrestricted by access modifiers "); System.out.println(dog.getDeclaredConstructor(String.class)); System.out.println(" Get all constructors, not restricted by access modifiers "); Constructor[] constructors2 = dog.getDeclaredConstructors(); for(Constructor constructor : constructors2) { System.out.println(constructor); }} @test // attribute public void filedTest() throws NoSuchFieldException {Class dog = dog.class; System.out.println(" Get the specified public property "); System.out.println(dog.getField("color")); System.out.println(" Get all public attributes "); Field[] fields1 = dog.getFields(); for(Field field : fields1) { System.out.println(field); } system.out.println (" Get the specified property, not restricted by access modifiers "); System.out.println(dog.getDeclaredField("unknown")); System.out.println(" Get all attributes, not restricted by access modifiers "); Constructor[] constructors2 = dog.getDeclaredConstructors(); Field[] fields2 = dog.getDeclaredFields(); for(Field field : fields2) { System.out.println(field); Public void mothodTest() throws NoSuchMethodException {Class dog = dog.class; System.out.println(" Get the specified public method "); System.out.println(dog.getMethod("run")); System.out.println(" Get all public methods "); Method[] methods1 = dog.getMethods(); for(Method method: methods1) { System.out.println(method); } system.out.println (" Get the specified method, unrestricted by access modifiers "); System.out.println(dog.getDeclaredMethod("fanzhi")); System.out.println(" Get all attributes, not restricted by access modifiers "); Method[] methods2 = dog.getDeclaredMethods(); for(Method method: methods2) { System.out.println(method); }} @ Test / / other Test public void otherTest () throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { Class dogClass = Dog.class; Dog dog = (Dog) dogClass.newInstance(); / / call the private Method fanzhi. = dogClass getDeclaredMethod (" fanzhi "); System.out.println(fanzhi.isAccessible()); // Whether the permission check is cancelled fanzhi.setaccessible (true); // Cancel permission check system.out.println (fanzhi.getmodiFIERS ()); // Invoke: 0, public: 1, private: 2, protected: 4, fanzhi.invoke(dog); // Execute method}}Copy the code

As you can see from the code above, using reflection allows permission checking to be removed, allowing methods that are not normally accessible to be accessed and executed, but it also breaks class encapsulation.

Summary: Reflection makes our code more flexible, but it also consumes more system resources, so if you don’t need to create an object dynamically, you don’t need to use reflection.