Java basic enhancement reflection mechanism

1 Introduction to reflection mechanism

The reflection mechanism of Java refers to that in the running state of a program, you can construct an object of any class, understand the class to which any object belongs, understand the member variables and methods of any class, and call the properties and methods of any object. This dynamic access to program information and the function of dynamically calling objects is called the reflection mechanism of Java language. Reflection is regarded as the key to dynamic language.

The concept of reflection was first proposed by programming developer Smith in 1982. It mainly refers to the ability of application program to access, detect and modify its own state and behavior. This concept immediately attracted the great attention of the programming community, and all kinds of research work began, which led to the programming revolution, and a variety of object-oriented languages supporting reflection mechanism emerged.

In the field of computer science, reflection is a kind of application that can describe and control itself. In Java programming language, reflection is a powerful tool and an implementation method of abstract programming. It can make code statements more flexible and greatly improve the ability of code matching when running.

2 Class class

For a bytecode file. Class, although we know nothing about the bytecode file on the surface, the file itself records a lot of information. When Java loads the. Class bytecode file, the JVM will generate a java.lang.Class object to represent the. Class bytecode file. Many basic information of the class can be obtained from the class object, which is the reflection mechanism. So in order to complete the reflection operation, we must first recognize the class class. [1]

The classes required for reflection mechanism mainly include class class in java.lang package and Constructor class, Field class, Method class and Parameter class in java.lang.reflet package. Class class is a special class, which is the basis of reflection mechanism. Class objects represent classes or interfaces in running Java programs. That is to say, when any class is loaded, the class. Class file (bytecode file) is read into memory, and a java.lang.Class object is automatically created for it. Class class has no public Constructor. Its object is created by the JVM by calling the defineClass() Method in the class loader when the class is loaded. Therefore, a class object cannot be created explicitly. Through this class object, other information of this object can be obtained

3 reflexive mind map

4. Reflection

4.1 preparations

1. New @ InheritedAnnotation annotation

@Target({ElementType.FIELD, ElementType.TYPE, ElementType.CONSTRUCTOR})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedAnnotation {
    String value();
}

2. New @ MyAnnotation annotation annotation

@Target({ElementType.FIELD, ElementType.TYPE, ElementType.CONSTRUCTOR})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();
}

3. Create a new Person class

@InheritedAnnotation("Inherited")
public class Person {

    private Integer id;

    public Person() {
    }

    public void say() {
        System.out.println("Hello Person");
    }
}

4. Create a new User class to inherit the Person class

@MyAnnotation("myAnnotation")
public class User extends Person {

    @MyAnnotation("name")
    public String name;

    @MyAnnotation("sex")
    private String sex;

    protected int age;

    public User() {
    }

    @MyAnnotation("User(name, sex, age)")
    public User(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    @MyAnnotation("name")
    private User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }

    private void sayHello() {
        System.out.println("Hello World");
    }
}

4.2 three ways to obtain Class

	/**
     * Three ways to get Class objects
     * @param obj
     * @return
     * @throws ClassNotFoundException
     */
    public static Class getClazz(Object obj) throws ClassNotFoundException {
        //The first way: obtain the Class object through the full pathname of the object
        Class clazz = Class.forName("com.base.domain.User");
        System.out.println("1,Get through the path of the object Class Participants:" + clazz);
        //The second way: get the Class object through the getClass method of the object
        Class clazz1 = obj.getClass();
        System.out.println("2,By object instance getClass Method acquisition Class Participants:" + clazz1);
        //The third way: obtain the class object through the. Class method of the object
        Class clazz2 = User.class;
        System.out.println("3,By object.class Method acquisition Class Participants:" + clazz2);
        return clazz;
    }

Implementation:

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        User user = new User();
        Class clazz = ReflectUtils.getClazz(user);
    }
}

Execution result:

1. Get the Class object through its path: class com.base.domain.User
 2. Get the Class object through the getClass method of the object instance: class com.base.domain.User
 3. Get the class object through the object. Class method: class com.base.domain.User

4.3 get all properties of the class

	/**
     * Get all properties of a class
     * @param clazz
     * @throws NoSuchFieldException
     */
    public static void getAllFields(Class clazz) throws NoSuchFieldException {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("Get all properties in the class:" + field);
        }
        Field field = clazz.getDeclaredField("name");
        System.out.println("Get the properties of the class by the property name:" + field);
    }

Execution result:

Get all the attributes in the class: public java.lang.String com.base.domain.User.name
 Get all the attributes in the class: private java.lang.String com.base.domain.User.sex
 Get all properties in the class: protected int com.base.domain.User.age
 Get the properties of the class through the property name: public java.lang.String com.base.domain.User.name

4.4 get the public properties of the class

	/**
     * Get public properties in class
     * @param clazz
     * @throws NoSuchFieldException
     */
    public static void getPublicFields(Class clazz) throws NoSuchFieldException {
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println("Get the co open properties in the class:" + field);
        }

        //The clazz.getField(String name) method cannot get private properties, and a NoSuchFieldException will be thrown
        Field field1 = clazz.getField("name");
        System.out.println("Get the public properties of the class through the property name:" + field1);
    }

Execution result:

Get the co open attribute in the class: public java.lang.String com.base.domain.User.name
 Get the public properties of the class through the property name: public java.lang.String com.base.domain.User.name

4.5 get all methods of this class

	/**
     * Get all methods in this class
     * @param clazz
     */
    public static void getAllMethods(Class clazz) throws NoSuchMethodException {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("Get all methods of this class:" + method);
        }

        Method method = clazz.getDeclaredMethod("setSex", String.class);
        System.out.println("Get by method name setSex Method" + method);
    }

Execution result:

Get all the methods of this class: public java.lang.String com.base.domain.User.toString()
Get all methods of this class: public java.lang.String com.base.domain.User.getName()
Get all methods of this class: public void com.base.domain.User.setName(java.lang.String)
Get all the methods of this class: public java.lang.String com.base.domain.User.getSex()
Get all methods of this class: public void com.base.domain.User.setSex(java.lang.String)
Get all methods of this class: public int com.base.domain.User.getAge()
Get all methods of this class: public void com.base.domain.User.setAge(int)
Get all the methods of this class: private void com.base.domain.User.sayHello()
Get setSex method public void com.base.domain.User.setSex(java.lang.String) by method name

4.6 access to the public methods of this class and its parent class

	/**
     * Get all public methods of this class and its parent class. Private methods will not be obtained
     * @param clazz
     */
    public static void getPublicMethods(Class clazz) throws NoSuchMethodException {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println("Get all the public methods of the class, including the methods of the parent class:" + method);
        }

        Method method = clazz.getMethod("getSex");
        System.out.println("Get by method name getSex Method" + method);
    }

Execution result:

Get all the public methods of the class, including the methods of the parent class: public java.lang.String com.base.domain.User.toString()
Get all the public methods of the class, including the methods of the parent class: public java.lang.String com.base.domain.User.getName()
Get all the public methods of the class, including the methods of the parent class: public void com.base.domain.User.setName(java.lang.String)
Get all the public methods of the class, including the methods of the parent class: public java.lang.String com.base.domain.User.getSex()
Get all the public methods of the class, including the methods of the parent class: public void com.base.domain.User.setSex(java.lang.String)
Get all the public methods of the class, including the methods of the parent class: public int com.base.domain.User.getAge()
Get all the public methods of the class, including the methods of the parent class: public void com.base.domain.User.setAge(int)
Get all the public methods of the class, including the methods of the parent class: public void com.base.domain.Person.say()
Get all the public methods of the class, including the methods of the parent class: public final void java.lang.Object.wait() throws java.lang.InterruptedException
 Get all the public methods of the class, including the methods of the parent class: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
 Get all the public methods of the class, including the methods of the parent class: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
 Get all the public methods of the class, including the methods of the parent class: public boolean java.lang.Object.equals(java.lang.Object)
Get all the public methods of the class, including the methods of the parent class: public native int java.lang.Object.hashCode()
Get all the public methods of the class, including the methods of the parent class: public final native java.lang.Class java.lang.Object.getClass()
Get all the public methods of the class, including the methods of the parent class: public final native void java.lang.Object.notify()
Get all the public methods of the class, including the methods of the parent class: public final native void java.lang.Object.notifyAll()
Get getSex method public java.lang.String com.base.domain.User.getSex() by method name

4.7 get all construction methods of the class

**
     * Get all construction methods of the class
     * @param clazz
     */
    public static void getAllConstructors(Class clazz) throws NoSuchMethodException {
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("Get all the construction methods of the class:" + constructor);
        }

        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        System.out.println("Obtain the construction method through the number and type of parameters:" + constructor);
    }

Execution result:

Get all the construction methods of the class: private com.base.domain.User(java.lang.String)
Get all the construction methods of the class: public com.base.domain.User(java.lang.String,java.lang.String,int)
Get all the construction methods of the class: public com.base.domain.User()
Obtain the construction method through the number and type of parameters: private com.base.domain.User(java.lang.String)

4.8 public construction method of obtaining class

	/**
     * Get the public constructor of the class
     * @param clazz
     */
    public static void getPublicConstructors(Class clazz) throws NoSuchMethodException {
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("Get the public constructor of the class:" + constructor);
        }
        Constructor constructor = clazz.getConstructor(String.class, String.class, int.class);
        System.out.println("Obtain the open construction method through the number and type of parameters:" + constructor);
    }

Execution result:

Get the public construction method of the class: public com.base.domain.User(java.lang.String,java.lang.String,int)
Get the public constructor of the class: public com.base.domain.User()
Obtain the public construction method through the number and type of parameters: public com.base.domain.User(java.lang.String,java.lang.String,int)

4.9 get notes on this class

	/**
     * Get annotation on class
     * @param clazz
     */
    public static void getClassAnnotations(Class clazz) {
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("Get annotation on class" + annotation);
        }

        Annotation annotation = clazz.getDeclaredAnnotation(MyAnnotation.class);
        System.out.println("Get annotation through annotation class:" + annotation);
    }

Execution result:

Get annotation on class @ com.base.annotation.MyAnnotation(value=myAnnotation)
Get annotation through annotation class: @ com.base.annotation.MyAnnotation(value=myAnnotation)

4.10 get comments of this class and its parent class

/**
 * Getting the annotation on the class will get the annotation decorated with @ Inherited in the parent class
 * @param clazz
 */
public static void getAnnotations(Class clazz) {
    Annotation[] annotations = clazz.getAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println("Get the inheritable class annotation in the parent class and the class annotation in this class" + annotation);
    }
    Annotation annotation = clazz.getAnnotation(InheritedAnnotation.class);
    System.out.println("Get annotation through annotation class:" + annotation);
}

Execution result:

Get the inheritable class annotation in the parent class and the class annotation in this class @ com.base.annotation.InheritedAnnotation(value=Inherited)
Get the inheritable class annotation in the parent class and the class annotation in this class @ com.base.annotation.MyAnnotation(value=myAnnotation)
Get annotation through annotation class: @ com.base.annotation.InheritedAnnotation(value=Inherited)

4.11 instantiating objects by reflection

	/**
     * Instantiate objects by reflection
     * @param clazz
     * @return
     * @throws Exception
     */
    public static  Object newInstanceObject(Class clazz) throws Exception {
        User user = (User)clazz.newInstance();
        System.out.println("adopt newInstance Method instanced object:" + user.toString());

        Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class, int.class);
        user = (User) constructor.newInstance("Zhang San", "male", 18);
        System.out.println("Instantiate an object through an open constructor:" + user.toString());

        constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);//Access to private methods and properties needs to be set to true
        user = (User) constructor.newInstance("Li Si");
        System.out.println("To instantiate an object through a private constructor:" + user.toString());

        return user;
    }

Execution result:

Instantiate the object through newInstance: User{name='null', sex='null', age=0}
Instantiate the object through the open construction method: User{name = 'Zhang San', sex = 'male', age=18}
Instantiate the object through a private constructor: User{name = 'Li Si', sex='null', age=0}

4.12 calling methods through reflection

/**
     * Call method by reflection
     * @param clazz
     * @throws Exception
     */
    public static void  invokeMethod(Class clazz) throws Exception {
        Method method = clazz.getDeclaredMethod("setAge", int.class);
        User user = (User) newInstanceObject(clazz);
        method.invoke(user, 28);
        System.out.println("Call by reflection setAge Method:" + user.toString());
    }

Execution result:

Call setAge method through reflection: User{name = 'Li Si', sex='null', age=28}

4.13 modifying attributes by reflection

	/**
     * Modifying attribute values by reflection
     * @param clazz
     * @throws Exception
     */
    public static void invokeUpdateField(Class clazz) throws Exception {
        Field field = clazz.getDeclaredField("sex");
        User user = (User) newInstanceObject(clazz);
        field.setAccessible(true);//If it is a public property, setAccessible is not required to be true
        field.set(user, "female");
        System.out.println("To modify the private property value of an object by reflection:" + user.toString());
    }

Execution result:

Modify the private property value of the object through reflection: User{name = 'Li Si', sex = 'female', age=0}

5 reflection significance

First of all, the reflection mechanism greatly improves the flexibility and expansibility of the program, reduces the coupling of modules, and improves its adaptability.

Second, the reflection mechanism allows the program to create and control objects of any class without hard coding the target class in advance.

Thirdly, the reflection mechanism can be used to construct the object of a class, judge the member variables and methods of a class, and call the methods of an object at runtime.

Finally, the reflection mechanism is the foundation of building framework technology. Using reflection can avoid writing code in the framework.

It is reflection that has the above characteristics, so it can compile and create objects dynamically, which greatly stimulates the flexibility of programming language, strengthens the feature of polymorphism, and further improves the abstract ability of object-oriented programming, so it is favored by the programming community.

6 reflection characteristics

Although reflection mechanism brings great flexibility and convenience, reflection also has disadvantages. The function of reflection mechanism is very powerful, but it can not be abused. When it is possible to finish without reflection, try not to use it for the following reasons:

1. Performance issues.

Java reflection mechanism contains some dynamic types, so Java virtual machine can not optimize these dynamic codes. Therefore, the efficiency of reflection operation is much lower than that of normal operation. We should avoid using reflection in programs that require high performance or code that is often executed. Moreover, how to use reflection determines the performance. If it's a less run part of the program, performance won't be an issue.

2. Security restrictions.

Using reflection usually requires that the program run without security restrictions. If a program requires security, it is best not to use reflection.

3. Program robustness.

Reflection allows code to perform operations that are not normally allowed, so using reflection can have unexpected consequences. Reflection code destroys the abstraction of Java program structure, so when the platform of program running changes, because the abstract logic structure can not be recognized, the effect of code will be different from before.

7 Summary

1. Calss.getAnnotations(); method to get annotations, the annotation of the parent class must contain the meta annotation @ Inherited to be obtained;

2. When instantiating an object or modifying a private property through a private constructor, setAccessible must be set to true for normal execution;

3. This article lists some common and important classes and methods used in the use of reflection mechanism. Please check the official documents for other uses.

Keywords: Java Programming jvm Attribute

Added by chopficaro on Fri, 03 Apr 2020 07:36:48 +0300