This is the 8th day of my participation in Gwen Challenge

Reflection mechanism

Reflection to create

Reflection, while the program is running, gets the properties and methods of the class

To be more specific, it can be divided into the following four points

  1. Gets the class to which the instance object belongs
  2. Gets member variables and methods in any class
  3. Calls the methods of the instance object
  4. Construct an instance object of the class

For a Java Class file, there are three ways to get a Class

  1. The getClass() method defined in the Object class, called through the instance Object
  2. Class name. Class, called directly
  3. Class.forname (), based on the path of the Class file
/* Instantiate the Object by calling the getClass() method defined in the Object class */
ArrayList<Integer> integers = new ArrayList<>();
System.out.println(integers.getClass().getName());

/* The second way is to get */ directly from the class name. Class
System.out.println(ArrayList.class.getName());

/* Get */ from the path where the class file is located
System.out.println(Class.forName("java.util.ArrayList"));
Copy the code

For the above three, it is recommended to use the class name. Class or class.forname ().

Note that only one Class file exists on the VM. The Class file obtained in the three methods is the same

In the Class Class, a number of methods are provided, some of which are briefly described, and the rest refer to the official API manual

  • String getName(): Gets the fully qualified name of the class file
  • Field[] getFields(): Gets the public properties of the class file
  • Field[] getDeclaredFields(): Gets all the attributes of the class file
  • Method[] getMethods(): Public method to get a class file
  • Method[] getDeclaredMethods(): Gets all the methods of the class file
  • Class<? > forName(String className): Gets and loads the class file according to the qualified name

When you use an ArrayList container, you cannot determine the actual capacity of the instance objects of the container

At this point, you can use Java’s reflection mechanism to obtain the capacity properties within the instance object

public static void main(String[] args) throws NoSuchFieldException {
    ArrayList<Integer> integers = new ArrayList<>();
    for (int i = 0; i < 150; i++) {
        System.out.println("The first" + i + "Element before adding:"+ get(integers)); integers.add(i); }}public static Integer get(ArrayList
        arrayList) {
    try {
        // Gets the specified property
        Field elementData = arrayList.getClass().getDeclaredField("elementData");
        // Set the property field to accessible
        elementData.setAccessible(true);
        // Actual value, return Object[]
        Object[] o = (Object[]) elementData.get(arrayList);
        return o.length;
    } catch (NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
    }
    return -1;
}
Copy the code

Below, we demonstrate the various parts of reflection using the ArrayList class

Field operations

  • Field[] getFields(): Gets all public fields. Including the parent class
  • Field[] getDeclaredFields(): Retrieves all fields, excluding the parent class
  • Field getField(String name): Gets the specified, public field
  • Field getDeclaredField(String name): gets the specified field
  • String getName(): Gets the name of the field
  • boolean isAccessible(boolean flag): Indicates whether the user has the access permission for the field
  • void setAccessible(boolean flag): Avoids the check and obtains the access permission for the field
  • Object get(Object obj): gets the value of the specified field in the specified object
  • void set(Object obj, Object value): sets the value of the specified field in the specified object
ArrayList<Integer> integers = new ArrayList<>();
Field defaultCapacity = integers.getClass().getDeclaredField("DEFAULT_CAPACITY");
defaultCapacity.setAccessible(true);
Object o = defaultCapacity.get(integers);
System.out.println(o);
for (Field field : integers.getClass().getDeclaredFields()) {
    field.setAccessible(true);
    System.out.println(field);
}
/*
10
private static final long java.util.ArrayList.serialVersionUID
private static final int java.util.ArrayList.DEFAULT_CAPACITY
private static final java.lang.Object[] java.util.ArrayList.EMPTY_ELEMENTDATA
private static final java.lang.Object[] java.util.ArrayList.DEFAULTCAPACITY_EMPTY_ELEMENTDATA
transient java.lang.Object[] java.util.ArrayList.elementData
private int java.util.ArrayList.size
private static final int java.util.ArrayList.MAX_ARRAY_SIZE
*/
Copy the code

Method of operation

  • Method[] getMethods(): Gets all the exposed methods of a class, including the parent class
  • Method[] getDeclaredMethods(): Gets all the methods in a class, excluding the parent class
  • Method getMethod(String name, Class<? >... parameterTypes): Gets the specified, public method of the class
  • Method getDeclaredMethod(String name, Class<? >... parameterTypes): gets the method specified in the class
  • String getName(): Gets the name of the method
  • void setAccessible(boolean flag): Indicates whether the user has the access permission for the method
  • Object invoke(Object obj, Object... args): Calls this method, passing the argument list
ArrayList<Integer> integers = new ArrayList<>();
Method add = integers.getClass().getDeclaredMethod("add", Object.class);
add.setAccessible(true);
add.invoke(integers, 120);
System.out.println(integers.get(0));
for (Method method : integers.getClass().getMethods()) {
    System.out.println(method);
}
/* 120 public boolean java.util.ArrayList.add(java.lang.Object) public void java.util.ArrayList.add(int,java.lang.Object) public boolean java.util.ArrayList.remove(java.lang.Object) public java.lang.Object java.util.ArrayList.remove(int) public java.lang.Object java.util.ArrayList.get(int) public boolean java.util.ArrayList.equals(java.lang.Object) public int java.util.ArrayList.hashCode() public java.lang.Object java.util.ArrayList.clone() ............ * /
Copy the code

It is worth noting that invoke(Object obj, Object… The obj argument can be set to null if args) calls static methods

Instance objects

Reflection can not only access and manipulate properties and methods, but also instantiate objects

  • T newInstance(): calls the no-argument construction of the class

Type judgment

  • boolean isArray(): Indicates whether it is an array
  • boolean isPrimitive(): Indicates whether it is an original type
  • boolean isInterface(): Indicates whether it is an interface
  • isEnum(): Indicates whether to enumerate
  • isAnnotation(): Indicates whether it is an annotation
  • isAnonymousClass(): Indicates whether it is an anonymous inner class
  • isMemberClass(): Indicates whether it is a member inner class
  • isLocalClass(): Whether it is a local class, that is, a local inner class
System.out.println(ArrayList.class.isArray());
System.out.println(ArrayList.class.isPrimitive());
System.out.println(ArrayList.class.isInterface());
System.out.println(ArrayList.class.isEnum());
System.out.println(ArrayList.class.isAnnotation());
System.out.println(ArrayList.class.isAnonymousClass());
System.out.println(ArrayList.class.isMemberClass());
System.out.println(ArrayList.class.isLocalClass());
/*
false
false
false
false
false
false
false
false
*/
Copy the code

Declaration of a class

  • int getModifiers(): Gets a class modifier that returns a hexadecimal text number
  • Class<? super T> getSuperclass(): Gets the parent class that the class inherits
  • Class<? >[] getInterfaces(): Gets the interface implemented by the class
  • Annotation[] getDeclaredAnnotations(): Gets an annotation of the class declaration
  • Annotation[] getAnnotations(): Gets annotations of the class declaration, including the parent class
// getModifiers() get hexadecimal text numbers for modifiers PUBLIC = 0x00000001; ABSTRACT = 0x00000400
System.out.println(ArrayList.class.getModifiers());
System.out.println(AbstractList.class.getModifiers());
/* 1,1025 */

// Get the parent of the current class. The parent of Object is null
System.out.println(ArrayList.class.getSuperclass());
/* class java.util.AbstractList */

// Get the interface implemented by the current class, return an array
System.out.println(Arrays.toString(ArrayList.class.getInterfaces()));
/* [interface java.util.List, interface java.util.RandomAccess, interface java.lang.Cloneable, interface java.io.Serializable] */
Copy the code

The inner class

  • Class<? >[] getClasses(): Gets all exposed inner classes, interfaces, including parent classes
  • Class<? >[] getDeclaredClasses(): Gets all inner classes and interfaces, excluding the parent class
  • Class<? > getDeclaringClass()If the current class is an inner class, get its outermost outer class
  • Class<? > getEnclosingClass(): Gets the directly contained outer class if the current class is an inner class
  • Method getEnclosingMethod(): Returns a method in an anonymous, local inner class
System.out.println(Arrays.toString(ArrayList.class.getClasses()));
/ * * / []
System.out.println(Arrays.toString(ArrayList.class.getDeclaredClasses()));
/* [ class java.util.ArrayList$ArrayListSpliterator, class java.util.ArrayList$SubList, class java.util.ArrayList$ListItr, class java.util.ArrayList$Itr ] */
Copy the code

Class loading

  • Class<? > forName(String className): Loads the class file according to the fully qualified name
  • Class<? > forName(String name, boolean initialize, ClassLoader loader)Load the class file and do some Settings
    • initialize: Whether to initialize the code block. Default is true
    • loader: class loader. Default is currentLoader

In the previous three ways reflection was created, time has run out and I won’t demonstrate it here

Class loaders, not necessary for now, but explained later

Primitive types are not supported in class loading, i.e. forName() cannot be used