Java reflection is an important one, and you’ll see reflection in a lot of places. It provides the Java language’s ability to load, explore, and use classes at runtime that are completely unknown at compile time. This capability is very common in framework writing, such as dynamic proxies and class scan parsing.

Definition and function of reflection

Reflection mechanism: The ability of the Java language to look at itself at runtime, to understand its own situation and prepare for the next action. It turns out that, at run time, for a class, we know what methods and attributes that class has. For an object, we can call any of its methods. This is the ability to dynamically retrieve information about a class and invoke object methods on the fly.

The basis for implementing reflection

Java provides reflection mechanisms that rely on Class classes and the java.lang.Reflect Class library. Its main classes are as follows:

  1. Class: indicates a Class or interface
  2. Field: Represents a member variable in a class
  3. Method: Represents a Method in a class
  4. Constructor: indicates the class Constructor
  5. Array: This class provides static methods for dynamically creating arrays and accessing Array elements

Class

The Class Class is the Java equivalent for representing runtime type information. In fact, every Class in Java has a Class object, and whenever we write and compile a newly created Class, we write the information to a.class file. When we create a new object or reference a static member variable, the Class loader subsystem in the JVM loads the corresponding Class object into the JVM, and the JVM then creates an instance object based on that type information or provides a reference value for the static variable. We can call a Class Class a Class type, and a Class object a Class object (see Thinking in Java).

The Class Class has the following characteristics:

  1. The Class Class is a Class, and Class is the keyword.
  2. Class classes have only one private constructor, and only the JVM can create instances of Class classes.
  3. For objects of the same Class, there is only one corresponding Class instance in the JVM to describe its type information. (Same class: same package name + same class name and loaded by the same classloader)

The.class file stores all the information about a class, such as all the methods, all the constructors, all the fields (member attributes), and so on. When the JVM starts, the associated classes are loaded into memory via a.class file as follows:

Method to get an instance of Class

As mentioned above, the Class Class has only one private constructor. So you can’t get an instance of Class using new.

/* * Constructor. Only the Java Virtual Machine creates Class * objects. */
private Class(a) {}
Copy the code
Class.forname () method

You can get an instance of a Class through its forName method, where the name of the Class is written to the full path of the Class. This method can only be used to get objects of class type that reference type.

// This method is loaded using the current Class loader and initializes the Class instanceClass<? > clazz = Class.forName("java.lang.String");
// The above call is equivalent toClass<? > clazz = Class.forName("java.lang.String".true, currentLoader);
Copy the code

Using this method may throw a ClassNotFoundException, which occurs during the loading phase of a class, for the following reasons:

  1. The classloader did not find the class in the classpath.
  2. The class has been loaded into JVM memory by one class loader, and another class loader tries to load it from the same package
Object. The getClass () method

If we have an Object of a Class, we can get the Class Object of that Class using object. getClass.

// The getClass method of String
Class clazz1 = "hello".getClass();
// The getClass method of an array object
Class clazz2 = (new byte[1024]).getClass();
System.out.println(class2) // Outputs [B, [for array, B for byte, the class type of the byte array
Copy the code
The class of grammar

If we know the name of the class type we want to get, we can use the class syntax to get objects of that class type.

/ / class
Class clazz = Integer.class;
/ / array
Class clazz2 = int [][].class;
Copy the code
Wrap the TYPE static property of the class

There are wrapper classes for both base types and void. There is a static attribute TYPE in the wrapper class that holds the class TYPE. The Integer class, for example, has the following static attributes defined in its source code:

/**
 * The {@code Class} instance representing the primitive type
 * {@code int}.
 *
 * @sinceJDK1.1 * /
@SuppressWarnings("unchecked")
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
Copy the code

To generate an instance of a Class:

Class clazz1 = Integer.TYPE;
Class clazz2 = Void.TYPE;
Copy the code
Class Class method

Class has the following methods to get other classes:

  1. Class.getsuperclass () : Gets the parent Class of this Class
  2. Class.getclasses () : Gets the Class array of all public classes, interfaces, and enumerations, including inherited ones
  3. Class.getdeclaredclasses () : Gets the Class array of all classes, interfaces, and enumerations explicitly declared for this Class
  4. (Class/Field/Method/Constructor). The getDeclaringClass () : access to the Class/property/Method/Constructor’s Class

Member & AccessibleObject

Member and AccessibleObject before we talk about Field, Method, and Constructor. Member is an interface that represents a Member of Class, and the first three classes are implementation classes.

AccessibleObject, a common parent of the Field, Method, and Constructor classes, provides the ability to mark reflected objects for use without default Java language access control checks. The setAccessible method lets you access the corresponding content by ignoring the access level. And AccessibleObject implements the AnnotatedElement interface, providing capabilities associated with retrieving annotations.

Field

Field provides information about a single property of a class or interface and the ability to access it dynamically.

Class provides methods to obtain Field objects as follows:

Method return value Method names Method statement
Field getDeclaredField(String name) Gets the (including private) field of the specified name, excluding inherited fields
Field[] getDeclaredField() Gets all (including private) fields of the Class or interface represented by the Class object, excluding inherited fields
Field getField(String name) Gets a public decorated field with the specified name, including inherited fields
Field[] getField() Gets the field whose modifier is public, containing the inherited field

The API related to Field is not listed globally, but can be viewed here.

Method

Method provides information about a single Method of a class or interface and the ability to access it dynamically.

Class provides methods to obtain Field objects as follows:

Method return value Method names Method statement
Method getDeclaredMethod(String name, Class<? >... parameterTypes) Returns a Method object with the specified argument that reflects the specified declared Method of the Class or interface represented by this Class object.
Method[] getDeclaredMethod() Returns an array of Method objects that reflect all methods declared by the Class or interface represented by this Class object, including public, protected, default (package) access, and private methods, but not inherited methods.
Method getMethod(String name, Class<? >... parameterTypes) Returns a Method object that reflects the specified public member methods of the Class or interface represented by this Class object.
Method[] getMethods() Returns an array of Method objects that reflect the public member methods of the Class or interface represented by this Class object (including those declared by the Class or interface and those inherited from superclasses and superinterfaces).

The API for Method can be viewed here.

Constructor

Constructor provides information about a class’s Constructor and the ability to access it dynamically.

Class provides methods to obtain the Constructor object as follows:

Method return value Method names Method statement
Constructor<T> getConstructor(Class<? >... parameterTypes) Returns a constructor object with public access for the specified argument type
Constructor<? > [] getConstructors() Returns an array of Constructor objects for all constructors that have public access
Constructor<T> getDeclaredConstructor(Class<? >... parameterTypes) Returns constructor objects of the specified parameter type, all declared (including private)
Constructor<? > [] getDeclaredConstructor() Returns all declared (including private) constructor objects

The Constructor API is not listed globally, but can be viewed here.

Array

Arrays are also a class in Java, and arrays provide static methods for dynamically creating arrays and accessing Array elements.

GetXXX (Object Array, int Index), passing in the array Object and subscript index, can get the value of this position.

Through the newInstance (Class
componentType, int Length) method, pass in the array type and length, create an array. As follows:

// The following two arrays are equivalent
int x[] = new int[10];
int y[] = (int[]) Array.newInstance(int.class, 10);
/ / output true
System.out.println(x.length == y.length);
Copy the code

Through the newInstance (Class
componentType, int… Dimensions) method to create a multidimensional array. As follows:

// The following two arrays are equivalent
int x[][] = new int[10] [10];
int y[][] = (int[][]) Array.newInstance(int.class, 10.10);
/ / output true
System.out.println(x.length == y.length);
Copy the code

Reflection application scenarios

Almost all Java frameworks use reflection, such as dynamic configuration: reading the values of a written configuration file, and then using reflection to set those values into a configuration class. In general, the application scenarios are as follows:

  1. Used in framework development, such as dynamic configuration
  2. Used in plug-in development, such as continuous integration
  3. Application of extended

Of course reflection has some disadvantages:

  1. The performance is low
  2. Readability is poor
  3. Errors can only be reported during run time