Wechat search: code nong StayUp

Home address: goZhuyinglong.github. IO

Source: github.com/gozhuyinglo…

1. Introduction

In an OOP world, everything is an object. That is, we can abstract anything into an object.

A Person, for example, can be abstracted as a Person class, instantiating an object with new Person(); A Duck, for example, can be abstracted as a Duck class or instantiated… Can these classes themselves be abstracted into a class? Java provides a special Class Class that describes the internal information of a Class and is the core Class for reflection.

The following is the content of this article:

2. Overview of Java reflection mechanism

Java Reflection allows applications to use the Reflection API at runtime to retrieve the internal information of any class or interface, and to directly manipulate the internal properties and methods of any object. The core Class for reflection is java.lang.class.

  • Once the class is loaded, one is generated in the method area of heap memoryClassObject of type.
  • ClassClasses have no exposed constructors, which are provided by class loadersdefineClassMethod. soClassObjects are not “new”; they are obtained by methods.
  • thisClassObjects have the complete structural information of a class, and there is only one classClassObject.

3. Obtain the Class object

There are four ways to get a Class object:

  1. Get by class object;
  2. Call class directly from the class;
  3. Get from Class. ForName;
  4. Get it from the class loader.

Here are four ways to get the Class object of the Person Class using code:

@Test
public void testClassFor(a) {

    // 1. Obtain it from the class instance
    Person person = new Person();
    Class<? extends Person> clazz1 = person.getClass();
    System.out.println("01 -" + clazz1);

    // 2. Call class directly from class
    Class<Person> clazz2 = Person.class;
    System.out.println("." + clazz2);

    // 3. Obtain the value from class. forNameClass<? > clazz3 =null;
    try {
        clazz3 = Class.forName("io.github.gozhuyinglong.reflection.Person");
    } catch (ClassNotFoundException e) {
        // This exception is thrown when the specified class cannot be found
        e.printStackTrace();
    }
    System.out.println("03 -" + clazz3);

    // 4. Get it from the class loader
    ClassLoader classLoader = this.getClass().getClassLoader(); Class<? > clazz4 =null;
    try {
        clazz4 = classLoader.loadClass("io.github.gozhuyinglong.reflection.Person");
    } catch (ClassNotFoundException e) {
        // This exception is thrown when the specified class cannot be found
        e.printStackTrace();
    }
    System.out.println("04 -" + clazz4);

    // hashCode is equal, indicating that the four methods are the same instance
    System.out.println("05 -" + clazz1.hashCode());
    System.out.println(06 - "" + clazz2.hashCode());
    System.out.println("07 -" + clazz3.hashCode());
    System.out.println("08 -" + clazz4.hashCode());

}
Copy the code

Output result:

01 - class io.github.gozhuyinglong.reflection.Person 02 - class io.github.gozhuyinglong.reflection.Person 03 - class io.github.gozhuyinglong.reflection.Person 04 - class io.github.gozhuyinglong.reflection.Person 05 - 721748895 06 - 721748895 07-721748895 08-721748895Copy the code

As you can see from the output above, the four Class objects have the same hashCode, indicating that the same object is obtained using all four methods.

4. Class objects for special classes and interfaces

Some special classes and interfaces are mentioned in the source code comments:

  • Enumerations are a kind.
  • An annotation is an interface.
  • The array also belongs to a reflection ofClassObject class. Arrays that have the same element type and dimension have the sameClassObject (that is, the element type is different, or the array dimension is different, itsClassObjects are also different).
  • Raw Java type (boolean.byte.char.short.int.long.float.double) and keywordsvoidAlso said toClassObject.

Verify this with the following code:

@Test
public void testClassOther(a) {

    // Enumeration is a kind
    Class<PersonEnum> clazz1 = PersonEnum.class;
    System.out.println("01 -" + clazz1);

    // Annotations are an interface
    Class<PersonAnnotation> clazz2 = PersonAnnotation.class;
    System.out.println("." + clazz2);

    // Arrays also belong to a Class that reflects an instance of Class
    Person[] personArray3 = new Person[1];
    Class<? extends Person[]> clazz3 = personArray3.getClass();
    System.out.println("03 -" + clazz3);

    // Arrays with the same element type and dimension have the same Class instance
    Person[] personArray4 = new Person[4]; Class<? > clazz4 = personArray4.getClass(); Person[][] personArray5 =new Person[1] []; Class<? > clazz5 = personArray5.getClass();// The hashCode of two one-dimensional arrays is equal, indicating the same instance
    System.out.println("04 -" + clazz3.hashCode());
    System.out.println("05 -" + clazz4.hashCode());
    // The hashCode of the one-dimensional array is not equal to that of the two-dimensional array
    System.out.println(06 - "" + clazz5.hashCode());

    // The primitive Java type and keyword void are also represented as Class instances
    Class<Integer> clazz6 = int.class;
    System.out.println("07 -" + clazz6);

    Class<Double> clazz7 = double.class;
    System.out.println("08 -" + clazz7);

    Class<Void> clazz8 = void.class;
    System.out.println("-" + clazz8);

}
Copy the code

Output result:

01 - class io.github.gozhuyinglong.reflection.PersonEnum
02 - interface io.github.gozhuyinglong.reflection.PersonAnnotation
03 - class [Lio.github.gozhuyinglong.reflection.Person;
04 - 721748895
05 - 721748895
06 - 1642534850
07 - int
08 - double
09 - void
Copy the code

Through the output results can be seen, as described in the source code.

5. Java Reflection API

Java provides a reflection API that consists of the Class Class and the java.lang.Reflect Class library. The library contains classes such as Field, Method, Constructor, etc. Objects of these types are created by the JVM at run time to represent corresponding members of unknown classes.

Reflection allows you to programmatically access the field, method, and constructor information of a loaded class and manipulate it with reflection within safe limits.

Here are some commonly used classes:

5.1 Class (Class)

The java.lang.Class Class is used to describe the internal information of a Class. Instances of Class can get packages, annotations, modifiers, names, superclasses, interfaces, and so on.

@Test
public void testClass(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Obtain the package path of the class
    Package aPackage = clazz.getPackage();
    System.out.println("01 -" + aPackage);

    // Get all annotations on the class
    Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
    for (Annotation temp : declaredAnnotations) {
        System.out.println("." + temp);
    }

    // Get the modifier on the class
    int modifiers = clazz.getModifiers();
    String modifier = Modifier.toString(modifiers);
    System.out.println("03 -" + modifier);

    // Get the class name
    String name = clazz.getName();
    System.out.println("04 -" + name);
    // Get the simple class name
    String simpleName = clazz.getSimpleName();
    System.out.println("05 -" + simpleName);

    // Get the immediate superclass
    Type genericSuperclass = clazz.getGenericSuperclass();
    System.out.println(06 - "" + genericSuperclass);

    // Get the directly implemented interface
    Type[] genericInterfaces = clazz.getGenericInterfaces();
    for (Type temp : genericInterfaces) {
        System.out.println("07 -"+ temp); }}Copy the code

Output result:

01 - package io.github.gozhuyinglong.reflection
02 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
03 - public final
04 - io.github.gozhuyinglong.reflection.Person
05 - Person
06 - class io.github.gozhuyinglong.reflection.PersonParent
07 - interface io.github.gozhuyinglong.reflection.PersonInterface
Copy the code

5.2 Constructor ()

Java. Lang. Reflect the Constructor provides information on the Constructor of a class. You can get annotation information, parameter types, and so on on the constructor.

@Test
public void testConstructor(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Get an instance of the constructor declared publicConstructor<? > constructor1 = clazz.getConstructor(String.class,int.class, PersonEnum.class);
    System.out.println("01 -" + constructor1);

    // Get all constructor instances declared publicConstructor<? >[] constructorArray1 = clazz.getConstructors();for(Constructor<? > constructor : constructorArray1) { System.out.println("." + constructor);
    }

    // Get an instance of the declared constructorConstructor<? > constructor2 = clazz.getDeclaredConstructor(String.class); System.out.println("03 -" + constructor2);

    // Get all declared constructor instancesConstructor<? >[] constructorArray2 = clazz.getDeclaredConstructors();for(Constructor<? > constructor : constructorArray2) { System.out.println("04 -" + constructor);
    }

    // Create an instance from the constructor
    Object o1 = constructor1.newInstance("Yang guo".25, PersonEnum.MAN);
    System.out.println("05 -" + o1);

    // With the constructor's accessibility flag set to true, instances can be created through private constructors
    constructor2.setAccessible(true);
    Object o2 = constructor2.newInstance("Little Dragon Lady");
    System.out.println(06 - "" + o2);

    // Get all the annotations on the constructor
    Annotation[] annotations = constructor1.getDeclaredAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println("07 -" + annotation);
    }

    // Get all the argument types on the constructor
    Type[] genericParameterTypes = constructor1.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        System.out.println("08 -"+ genericParameterType); }}Copy the code

Output result:

01 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum) 02 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum) 02 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int) 02 - public io.github.gozhuyinglong.reflection.Person() 03 - private io.github.gozhuyinglong.reflection.Person(java.lang.String) 04 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum) 04 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int) 04 - private io.github.gozhuyinglong.reflection.Person(java.lang.String) 04 - public io.github.gozhuyinglong.reflection.Person() 05 - Person{name=' Person ', age=25, sex='MAN'} 06 - Person{name=' Person ', age=0, sex='null'} 07 - @io.github.gozhuyinglong.reflection.PersonAnnotation() 08 - class java.lang.String 08 - int 08 - class io.github.gozhuyinglong.reflection.PersonEnumCopy the code

5.3 Field (Attributes)

Java.lang.reflect. Field provides property information for the class. You can get annotations, modifiers, property types, property names, and so on on properties.

@Test
public void testField(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Gets a property declared public in the class or its parent
    Field field1 = clazz.getField("hobby");
    System.out.println("01 -" + field1);

    // Get all properties declared public in this class and its parent
    Field[] fieldArray1 = clazz.getFields();
    for (Field field : fieldArray1) {
        System.out.println("." + field);
    }

    // Get an attribute declared in this class
    Field field2 = clazz.getDeclaredField("name");
    System.out.println("03 -" + field2);

    // Get all declared attributes in the class
    Field[] fieldArray2 = clazz.getDeclaredFields();
    for (Field field : fieldArray2) {
        System.out.println("04 -" + field);
    }

    // Get all annotations on this property
    Annotation[] declaredAnnotations = field2.getDeclaredAnnotations();
    for (Annotation declaredAnnotation : declaredAnnotations) {
        System.out.println("05 -" + declaredAnnotation);
    }

    // Get the modifier
    String modifier = Modifier.toString(field2.getModifiers());
    System.out.println(06 - "" + modifier);

    // Get the property type, return the class objectClass<? > type = field2.getType(); System.out.println("07 -" + type);
    // Get the property Type, return the Type object
    Type genericType = field2.getGenericType();
    System.out.println("08 -" + genericType);

    // Get the attribute name
    String name = field2.getName();
    System.out.println("-" + name);

}
Copy the code

Output result:

01 - public java.lang.String io.github.gozhuyinglong.reflection.PersonParent.hobby
02 - public int io.github.gozhuyinglong.reflection.Person.height
02 - public java.lang.String io.github.gozhuyinglong.reflection.PersonParent.hobby
03 - private java.lang.String io.github.gozhuyinglong.reflection.Person.name
04 - private java.lang.String io.github.gozhuyinglong.reflection.Person.name
04 - private int io.github.gozhuyinglong.reflection.Person.age
04 - public int io.github.gozhuyinglong.reflection.Person.height
05 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
06 - private
07 - class java.lang.String
08 - class java.lang.String
09 - name
Copy the code

5.4 Method

Java.lang.reflect. Method provides Method information for a class. You can get annotations, modifiers, return value types, method names, and all parameters on a method.

@Test
public void testMethod(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Get a method declared public in this class and its parent class
    Method method = clazz.getMethod("setName", String.class);
    System.out.println("01 -" + method);

    // Get all methods declared public in this class and its parent
    Method[] methods = clazz.getMethods();
    for (Method temp : methods) {
        System.out.println("." + temp);
    }

    // Get a method declared in this class
    Method declaredMethod = clazz.getDeclaredMethod("display");
    System.out.println("03 -" + declaredMethod);

    // Get all methods declared in this class
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (Method temp : declaredMethods) {
        System.out.println("04 -" + temp);
    }

    // Get all annotations on the method
    Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
    for (Annotation temp : declaredAnnotations) {
        System.out.println("05 -" + temp);
    }

    // Get the modifier
    String modifier = Modifier.toString(method.getModifiers());
    System.out.println(06 - "" + modifier);

    // Get the return value type, return the class objectClass<? > returnType = method.getReturnType(); System.out.println("07 -" + returnType);
    // Get the return value Type, return the Type object
    Type genericReturnType = method.getGenericReturnType();
    System.out.println("08 -" + genericReturnType);

    // Get the method name
    String name = method.getName();
    System.out.println("-" + name);

    // Get all input parameters
    Parameter[] parameters = method.getParameters();
    for (Parameter temp : parameters) {
        System.out.println("10 -"+ temp); }}Copy the code

Output result:

01 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.toString()
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.getName()
02 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
02 - public int io.github.gozhuyinglong.reflection.Person.getAge()
02 - public void io.github.gozhuyinglong.reflection.Person.setAge(int)
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.sayHello()
02 - public io.github.gozhuyinglong.reflection.PersonEnum io.github.gozhuyinglong.reflection.PersonParent.getSex()
02 - public void io.github.gozhuyinglong.reflection.PersonParent.setSex(io.github.gozhuyinglong.reflection.PersonEnum)
02 - public final void java.lang.Object.wait() throws java.lang.InterruptedException
02 - public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
02 - public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
02 - public boolean java.lang.Object.equals(java.lang.Object)
02 - public native int java.lang.Object.hashCode()
02 - public final native java.lang.Class java.lang.Object.getClass()
02 - public final native void java.lang.Object.notify()
02 - public final native void java.lang.Object.notifyAll()
03 - private java.lang.String io.github.gozhuyinglong.reflection.Person.display()
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.toString()
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.getName()
04 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
04 - private java.lang.String io.github.gozhuyinglong.reflection.Person.display()
04 - public int io.github.gozhuyinglong.reflection.Person.getAge()
04 - public void io.github.gozhuyinglong.reflection.Person.setAge(int)
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.sayHello()
05 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
06 - public
07 - void
08 - void
09 - setName
10 - java.lang.String arg0
Copy the code

5.5 Modifier

Java. Lang. Reflect the Modifier provides information access Modifier. The access Modifier, which is an integer, can be obtained from objects such as Class, Field, Method, Constructor, etc. The Modifier description can be viewed through the modifiers. ToString Method. It also provides static methods and constants to decode access modifiers.

@Test
public void testModifier(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Get the class modifier value
    int modifiers1 = clazz.getModifiers();
    System.out.println("01 -" + modifiers1);

    // Gets the modifier value of the property
    int modifiers2 = clazz.getDeclaredField("name").getModifiers();
    System.out.println("." + modifiers2);

    // Get the modifier value of the constructor
    int modifiers3 = clazz.getDeclaredConstructor(String.class).getModifiers();
    System.out.println("03 -" + modifiers3);

    // Get the modifier value of the method
    int modifiers4 = clazz.getDeclaredMethod("display").getModifiers();
    System.out.println("04 -" + modifiers4);

    // Determine whether the modifier value is final
    boolean isFinal = Modifier.isFinal(modifiers1);
    System.out.println("05 -" + isFinal);

    // Determine whether the modifier value is of type public
    boolean isPublic = Modifier.isPublic(modifiers2);
    System.out.println(06 - "" + isPublic);

    // Based on the modifier value, get the string that the modifier flags
    String modifier = Modifier.toString(modifiers1);
    System.out.println("07 -" + modifier);
    System.out.println("08 -" + Modifier.toString(modifiers2));

}
Copy the code

Output result:

01 - 17
02 - 2
03 - 2
04 - 2
05 - true
06 - false
07 - public final
08 - private
Copy the code

5.6 Parameter

Java. Lang. Reflect the Parameter provides a method of Parameter information. You can get annotations on methods, parameter names, parameter types, and so on.

@Test
public void testParameter(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Get the constructor argumentConstructor<? > constructor = clazz.getConstructor(String.class,int.class, PersonEnum.class);
    Parameter[] parameterArray1 = constructor.getParameters();
    for (Parameter temp : parameterArray1) {
        System.out.println("01 -" + temp);
    }

    // Get method parameters
    Method method = clazz.getMethod("setName", String.class);
    Parameter[] parameterArray2 = method.getParameters();
    for (Parameter temp : parameterArray2) {
        System.out.println("." + temp);
    }

    Parameter parameter = parameterArray1[0];
    // Get annotations on parameters
    Annotation[] annotationArray = parameter.getAnnotations();
    for (Annotation temp : annotationArray) {
        System.out.println("." + temp);
    }

    // Get the parameter name
    String name = parameter.getName();
    System.out.println("03 -" + name);

    // Get the parameter type
    Type parameterizedType = parameter.getParameterizedType();
    System.out.println("04 -"+ parameterizedType); Class<? > type = parameter.getType(); System.out.println("05 -" + type);

}
Copy the code

Output result:

01 - java.lang.String arg0
01 - int arg1
01 - io.github.gozhuyinglong.reflection.PersonEnum arg2
02 - java.lang.String arg0
02 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
03 - arg0
04 - class java.lang.String
05 - class java.lang.String
Copy the code

5.7 AccessibleObject

Java. Lang. Reflect AccessibleObject class is Field, Method, and the superclass Constructor class.

This class provides the ability to check access control of classes, methods, and constructors (e.g., private methods only allow access to the current class).

This access check is performed when setting/getting properties, calling methods, and creating/initializing instances of classes.

Access checking is turned off by setting the accessibility flag to true (the default is false) using the setAccessible method. In this way, even private properties, methods, or constructors can be accessed.

6. Create objects and execute methods dynamically through reflection

Reflection can be used to create objects and execute methods, as shown in the following code example:

  • throughClassOf the classnewInstanceCreate an instance. (This method calls the no-parameter constructor).
  • By constructorConstructorClass to create an instance.
  • Get the method, and then passinvokeMethod, the first argument is instance, the following argument is methodParameter.
  • Gets the field, and because the age field is private, makes it accessible (leaving it unset raises an exception). And through thesetMethod to assign a value.
@Test
public void testInvoke(a) throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // Create an instance through newInstance of the Class. (This method calls the no-parameter constructor)
    Object o1 = clazz.newInstance();
    System.out.println("01 -" + o1.toString());

    Create an instance from the Constructor classConstructor<? > constructor = clazz.getConstructor(String.class,int.class, PersonEnum.class);
    Object o2 = constructor.newInstance("Yang guo".25, PersonEnum.MAN);
    System.out.println("." + o2.toString());

    // Invoke a method with an instance as the first argument and a Parameter as the method's Parameter
    Method method = clazz.getMethod("setName", String.class);
    method.invoke(o1, "Little Dragon Lady");
    System.out.println("03 -" + o1.toString());

    // Get the field, because the age field is private, so make it accessible (not setting it will raise an exception). And the value is assigned by the set method
    Field field = clazz.getDeclaredField("age");
    field.setAccessible(true);
    field.set(o1, 28);
    System.out.println("04 -" + o1.toString());

}
Copy the code

Execution Result:

01 - Person{name=' id ', age=0, sex=' id '} 02 - Person{name=' id ', age=25, sex=' id '} 03 - Person{name=' id ', age=0, sex=' id '} Sex ='null'} Person{name=' Person ', age=28, sex='null'}Copy the code

7. Disadvantages of reflection

From the official guide: docs.oracle.com/javase/tuto…

Reflection, while powerful, should not be used arbitrarily. If you can perform an operation without reflection, avoid it. Because there are the following disadvantages when accessing code through reflection.

7.1 Performance Overhead

Reflection includes some dynamic typing, so the JVM cannot optimize this code. Therefore, reflective operations are much less efficient than those that are not. We should avoid using reflection in code that is frequently executed or in programs that require high performance.

7.2 Security Restrictions

Using reflection requires that the program be run in an environment with no security restrictions. This is a problem if a program must run in an environment with security restrictions, such as an Applet.

7.3 Internal Exposure

Reflection allows code to perform operations that are not normally allowed, such as accessing private properties and methods. So using reflection can have unintended side effects: the code is functionally incorrect and portability is reduced. Reflecting code breaks abstractness, so when the platform changes, it is possible for the code to behave as well.

8. Complete code

Complete code please visit my Github, if you are helpful, welcome to ⭐, thank you ~~🌹🌹🌹

Github.com/gozhuyinglo…

9. Reference materials

  • Java™ Platform, Standard Edition 8 API Specification
  • The Java ™ Tutorials