The article comes from blog.csdn.net/gozhuyinglo…

Wechat search: Java source code source code share: 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() { // 1. Person = new Person(); Class<? extends Person> clazz1 = person.getClass(); System.out.println("01 - " + clazz1); Class<Person> clazz2 = person.class; System.out.println("02 - " + clazz2); // 3. Get Class<? > clazz3 = null; try { clazz3 = Class.forName("io.github.gozhuyinglong.reflection.Person"); } catch (ClassNotFoundException e) {// This exception is thrown when the specified class is not found. } System.out.println("03 - " + clazz3); 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 is not found. } System.out.println("04 - " + clazz4); System.out.println("05 - "+ clazz1.hashCode()); System.out.println("06 - " + clazz2.hashCode()); System.out.println("07 - " + clazz3.hashCode()); System.out.println("08 - " + clazz4.hashCode()); } 12345678910111213141516171819202122232425262728293031323334353637383940Copy 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-721748895 12345678Copy 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() {Class<PersonEnum> clazz1 = PersonEnum. Class; System.out.println("01 - " + clazz1); Class<PersonAnnotation> clazz2 = PersonAnnotation. Class; System.out.println("02 - " + clazz2); Person[] personArray3 = new Person[1]; Class<? extends Person[]> clazz3 = personArray3.getClass(); System.out.println("03 - " + clazz3); Person[] personArray4 = new Person[4]; Person[] personArray4 = new Person[4]; Class<? > clazz4 = personArray4.getClass(); Person[][] personArray5 = new Person[1][]; Class<? > clazz5 = personArray5.getClass(); System.out.println("04 - "+ clazz3.hashCode())); System.out.println("05 - " + clazz4.hashCode()); System.out.println("06 - "+ clazz5.hashCode())); 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("09 - " + clazz8); } 12345678910111213141516171819202122232425262728293031323334353637383940Copy 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 123456789Copy 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() throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person"); Package aPackage = clazz.getPackage(); System.out.println("01 - " + aPackage); / / get all comments the Annotation on the class [] declaredAnnotations = clazz. GetDeclaredAnnotations (); for (Annotation temp : declaredAnnotations) { System.out.println("02 - " + temp); } // get the class modifier int modiFIERS = clazz.getmodifiers (); String modifier = Modifier.toString(modifiers); System.out.println("03 - " + modifier); String name = clazz.getName(); System.out.println("04 - " + name); String simpleName = clazz.getSimplename (); System.out.println("05 - " + simpleName); / / to get immediate superclass Type genericSuperclass = clazz. GetGenericSuperclass (); System.out.println("06 - " + genericSuperclass); / / to get immediate implementation of the interface Type [] genericInterfaces = clazz. GetGenericInterfaces (); for (Type temp : genericInterfaces) { System.out.println("07 - " + temp); }} 12345678910111213141516171819202122232425262728293031323334353637Copy 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
1234567
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() throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person"); // Get an instance of the Constructor declared public. Constructor<? > constructor1 = clazz.getConstructor(String.class, int.class, PersonEnum.class); System.out.println("01 - " + constructor1); // Get all Constructor instances declared public Constructor<? >[] constructorArray1 = clazz.getConstructors(); for (Constructor<? > constructor : constructorArray1) { System.out.println("02 - " + constructor); } // Get an instance of the declared Constructor. Constructor<? > constructor2 = clazz.getDeclaredConstructor(String.class); System.out.println("03 - " + constructor2); // Get all declared Constructor instances. Constructor<? >[] constructorArray2 = clazz.getDeclaredConstructors(); for (Constructor<? > constructor : constructorArray2) { System.out.println("04 - " + constructor); } // Create an instance according to the constructor. Object o1 = constructor1.newInstance(" Yang guan ", 25, PersonEnum.MAN); System.out.println("05 - " + o1); / / the constructor can be accessed after the mark is set to true, you can create instances through private constructor constructor2. SetAccessible (true); Object O2 = constructor2. NewInstance (" xiaolong female "); 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 parameters on the constructor Type Type [] genericParameterTypes = constructor1. GetGenericParameterTypes (); for (Type genericParameterType : genericParameterTypes) { System.out.println("08 - " + genericParameterType); }} 12345678910111213141516171819202122232425262728293031323334353637383940414243444546Copy 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.PersonEnum 123456789101112131415Copy 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() throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person"); Field field1 = clazz.getField("hobby"); System.out.println("01 - " + field1); Field[] fieldArray1 = clazz.getFields(); for (Field field : fieldArray1) { System.out.println("02 - " + field); } // Get a property declared in this class Field field2 = clazz.getDeclaredField("name"); System.out.println("03 - " + field2); FieldArray2 = clazz.getDeclaredFields(); Field[] fieldArray2 = clazz.getDeclaredFields(); for (Field field : fieldArray2) { System.out.println("04 - " + field); } / / get all the annotations of this property on the Annotation [] declaredAnnotations = field2. GetDeclaredAnnotations (); for (Annotation declaredAnnotation : declaredAnnotations) { System.out.println("05 - " + declaredAnnotation); } // Get modifier String modifier = modificer.toString (field2.getModifiers()); System.out.println("06 - " + modifier); // Get the attribute type, return the Class<? > type = field2.getType(); System.out.println("07 - " + type); Type genericType = field2.getGenericType(); System.out.println("08 - " + genericType); String name = field2.getName(); System.out.println("09 - " + name); } 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647Copy 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
123456789101112
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() throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person"); Method = clazz.getMethod("setName", string.class); System.out.println("01 - " + method); [] methods = clazz.getmethods (); for (Method temp : methods) { System.out.println("02 - " + temp); DeclaredMethod = clazz.getDeclaredMethod("display"); System.out.println("03 - " + declaredMethod); [] declaredMethods = clazz.getDeclaredMethods(); for (Method temp : declaredMethods) { System.out.println("04 - " + temp); } / / get all the annotations of the method on the Annotation [] declaredAnnotations = method. The getDeclaredAnnotations (); for (Annotation temp : declaredAnnotations) { System.out.println("05 - " + temp); } // Get modifier String modifier = modificer.toString (method.getModifiers()); System.out.println("06 - " + modifier); // Get the return value type, return the Class<? > returnType = method.getReturnType(); System.out.println("07 - " + returnType); / / get the return value Type, Type, the Type object returned genericReturnType = method. The getGenericReturnType (); System.out.println("08 - " + genericReturnType); String name = method.getName(); System.out.println("09 - " + name); Parameter[] parameters = method.getParameters(); for (Parameter temp : parameters) { System.out.println("10 - " + temp); }} 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253Copy 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
12345678910111213141516171819202122232425262728293031
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() throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person"); Int modifiers1 = clazz.getModiFIERS (); // Get class modifiers1 = clazz.getModifiers(); System.out.println("01 - " + modifiers1); Int modifierS2 = clazz.getDeclaredField("name").getModifiers(); System.out.println("02 - " + modifiers2); / / get the constructor of the modifier values int modifiers3 = clazz. GetDeclaredConstructor (String. The class). GetModifiers (); System.out.println("03 - " + modifiers3); Int modifierS4 = clazz.getDeclaredMethod("display").getmodifiers (); System.out.println("04 - " + modifiers4); Boolean isFinal = Modifier. IsFinal (modifierS1); System.out.println("05 - " + isFinal); Public Type Boolean isPublic = Modifier. IsPublic (modifierS2); System.out.println("06 - " + isPublic); String modifier = modifier.toString (modifierS1); System.out.println("07 - " + modifier); System.out.println("08 - " + Modifier.toString(modifiers2)); } 12345678910111213141516171819202122232425262728293031323334Copy the code

Output result:

01 - 17
02 - 2
03 - 2
04 - 2
05 - true
06 - false
07 - public final
08 - private
12345678
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() throws Exception { Class<? > clazz = Class.forName("io.github.gozhuyinglong.reflection.Person"); // Get the Constructor argument Constructor<? > constructor = clazz.getConstructor(String.class, int.class, PersonEnum.class); Parameter[] parameterArray1 = constructor.getParameters(); for (Parameter temp : parameterArray1) { System.out.println("01 - " + temp); Method = clazz.getMethod("setName", string.class); Parameter[] parameterArray2 = method.getParameters(); for (Parameter temp : parameterArray2) { System.out.println("02 - " + temp); } Parameter parameter = parameterArray1[0]; Annotation[] annotationArray = parameter.getanannotations (); for (Annotation temp : annotationArray) { System.out.println("02 - " + temp); } // Get parameter name String name = parameter.getName(); System.out.println("03 - " + name); / / get parameter Type Type parameterizedType = parameter. GetParameterizedType (); System.out.println("04 - " + parameterizedType); Class<? > type = parameter.getType(); System.out.println("05 - " + type); } 123456789101112131415161718192021222324252627282930313233343536Copy 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
12345678
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:

  • Create an instance through newInstance of the Class Class. (This method calls the no-parameter constructor).

  • Create an instance from the Constructor class.

  • Retrieves a method and invokes it with the invoke method, the first Parameter being an instance, followed by the Parameter of the method.

  • Gets the field, and because the age field is private, makes it accessible (leaving it unset raises an exception). And the value is assigned by the set method.

    @Test public void testInvoke() throws Exception { Class<? > clazz = Class.forName(“io.github.gozhuyinglong.reflection.Person”);

    // Create an instance through newInstance of the Class. Object o1 = clazz.newinstance (); System.out.println("01 - " + o1.toString()); // Create an instance of Constructor<? > constructor = clazz.getConstructor(String.class, int.class, PersonEnum.class); Object o2 = constructor. NewInstance (" Yang guan ", 25, PersonEnum.MAN); System.out.println("02 - " + o2.toString()); Clazz.getmethod ("setName", string.class); clazz.getMethod("setName", String. Method.invoke (O1, "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). Clazz. getDeclaredField("age"); clazz.getDeclaredField("age"); field.setAccessible(true); field.set(o1, 28); System.out.println("04 - " + o1.toString());Copy the code

    } 12345678910111213141516171819202122232425

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 '} Person{name=' Person ', age=28, sex=' Person '} Person{name=' Person ', age=28, sex=' Person '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