Java reflection mechanism--the soul of framework design (detailed explanation)

Table of contents

1. Overview of reflection

1. What is reflection

2. The principle of reflection

3. What is the use of reflection mechanism

4. Classes related to reflection mechanism

2. The use of reflection

1. Determine the class to which any object belongs

(1) Which types have Class objects

(2) Three ways to get the Class object

(3) Determine the class to which any object belongs

2. Construct an object of any class

(1) Get the constructor

(2) Instantiate the object

3. Get the properties and methods of any class

(1) attributes

(2) method

4. Call the properties and methods of any object

(1) Get the properties of the modified object

(2) Call the method of the object

5. Generate dynamic proxy

3. Advantages, disadvantages and optimization of the reflection mechanism

1. Advantages and disadvantages of reflection

(1) Advantages

(2) Disadvantages

(3) Applicable scenarios of the reflection mechanism

2. Reflective call optimization

(1) Comparison of traditional methods and reflection calls before reflection call optimization

(2) Reflective call optimization - turn off access check

(3) After the reflection call is optimized, the comparison between the traditional method and the reflection call


1. Overview of reflection

1. What is reflection

Java is an object-oriented programming language. In the Java world, everything is an object. An object is an instantiation of a class, and the abstraction of an object is a class. A class in Java is usually composed of species elements, namely attributes, methods, constructors, blocks, and inner classes.

Then can we do it: For any class, we can know all the properties and methods of this class; for any object, we can call any of its methods and properties?

The answer is yes. How to get it? The reflection mechanism of the Java language.

Since everything in the Java world is an object, why can't our class attributes, class methods, and class construction methods be regarded as objects? ! And this is the reflection mechanism of Java. Reflection is to map various elements in the Java class into Java objects one by one.

Get the mapped attribute, we can change the value of the attribute; get the mapped method, we can call it to execute the corresponding method; get the mapped construction method, we can use it to construct the object .

2. The principle of reflection

We know that the running process of Java is as follows:

 Through the JVM, Java achieves platform independence. The Java source files we have written are first compiled into bytecode files by the Java compiler (that is, the "machine language" of the JVM), and the JVM is responsible for interpreting and executing Java bytes. code file to run the program. Let's take a look at the process of class loading:

  • JVM loads our class file
  • The JVM goes to our local disk to find the class file and loads it into the JVM memory
  • When the class file is read into the memory, the JVM creates an instance of the Class type for it and associates it

That is, a class only generates one Class instance, that is, behind different object instances of a class, it corresponds to the same Class instance. The Class instance of a class contains all the complete information of the class. If we obtain the Class instance of a certain class or object, we can get all the information of the corresponding class through it.

3. What is the use of reflection mechanism

Reflection is the soul of frame design. Reflection can control the program without modifying the source code (modifying the configuration file), and it also conforms to the ocp principle of the design pattern (opening and closing principle).

  • Determine the class of any object at runtime
  • Construct an object of any class at runtime
  • Get the member variables and methods of any class at runtime
  • Call member variables and methods of any object at runtime
  • Generate dynamic proxy

4. Classes related to reflection mechanism

kind meaning
java.lang.Class Represents the entire bytecode. Represents the entire class.
java,lang.reflect.Method Represents a method bytecode in bytecode. Represents a method in a class.
java.lang.reflect.Constructor Represents the constructor bytecode in the bytecode. Represents a constructor in a class.
java.lang.reflect.Field Represents an attribute bytecode in the bytecode. Represents member variables (static variables + instance variables) in the class.
java.util.Properties Read Java configuration files (.properties files)

2. The use of reflection

We now have two classes Animal.java and Person.java:

package com.senxu;

public class Animal {

    public String name="小动物";
    public String type="小狗";
    private int num=0;

    public Animal(){}

    public Animal(String type){
        this.type=type;
    }

    private Animal(int num){}

    public void hi(){
        //System.out.println("汪汪汪");
    }

    public static void hello(){
        System.out.println("你好");
    }

}
package com.senxu;

public class Person {

    public String name="我是人";
    public String type="中国人";

    public Person(){}

    public Person(String type){
        this.type=type;
    }

    public void hi(){
        //System.out.println("hello");
    }

}

There is a configuration file re.properties:

classpathAnimal=com.senxu.Animal
classpathPerson=com.senxu.Person
method=hi
methodHello=hello
varName=name
varType=type
varNum=num

 

1. Determine the class to which any object belongs

(1) Which types have Class objects

  • Outer class, member inner class, static inner class, local inner class, anonymous inner class
  • interf: interface
  • array
  • enum: enumeration
  • annotation: annotation
  • basic data type
  • void

(2) Three ways to get the Class object

  • Class.forname("full class name of the class") (recommended)

        Premise: The full class name of a class is known, and the class is in the class path, which can be obtained through the static method forName() of the Class class, and ClassNotFoundException may be thrown

        Application scenarios: mostly used for configuration files, reading the full path of classes, and loading classes

  • class.class

        Premise: If the specific class is known, it can be obtained through the class of the class. This method is the most safe and reliable, and the program performance is the highest

        Application scenario: mostly used for parameter passing, such as obtaining the corresponding constructor object through reflection

  • object.getClass()

        Premise: An instance of a certain class is known, and the getClass() method of the instance is called to obtain the Class object

        Application scenario: Get the Class object by creating a good object

  • The class loader gets the Class object
package com.senxu.class_;

import com.senxu.Animal;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class GetClass {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        //1.Class.forName()
        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        Class cls1 = Class.forName(classpath);
        System.out.println(cls1);

        //2.类名.class
        Class cls2 = Animal.class;
        System.out.println(cls2);

        //3.对象.getClass()
        Animal animal = new Animal();
        Class cls3 = animal.getClass();
        System.out.println(cls3);

        //4.通过类加载器来获取类的Class对象
        //(1)先得到类加载器
        ClassLoader classLoader = animal.getClass().getClassLoader();
        //(2)通过类加载器得到Class对象
        Class cls4 = classLoader.loadClass(classpath);
        System.out.println(cls4);

    }

}
class com.senxu.Animal
class com.senxu.Animal
class com.senxu.Animal
class com.senxu.Animal

 

(3) Determine the class to which any object belongs

package com.senxu.class_;


import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class Class1 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpathAnimal = properties.get("classpathAnimal").toString();
        String classpathPerson = properties.get("classpathPerson").toString();

        Class cls1 = Class.forName(classpathAnimal);
        Class cls2 = Class.forName(classpathAnimal);
        Class cls3 = Class.forName(classpathPerson);

        if (cls1.equals(cls2)) {
            System.out.println("equals");
            System.out.println(cls1);
        }
        else{
            System.out.println("!equals");
        }

        System.out.println("===================");

        if (cls1.equals(cls3)) {
            System.out.println("equals");
            System.out.println(cls1);
        }
        else{
            System.out.println("!equals");
        }

    }

}
equals
class com.senxu.Animal
===================
!equals

2. Construct an object of any class

(1) Get the constructor

package com.senxu;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Properties;

public class Reflection3 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        Class cls = Class.forName(classpath);

        //获取该类的所有公共构造器
        Constructor[] constructors = cls.getConstructors();
        for (Constructor constructor:constructors){
            System.out.println(constructor);
        }

        System.out.println("==================");

        //获取该类的所有构造器
        constructors = cls.getDeclaredConstructors();
        for (Constructor constructor:constructors){
            System.out.println(constructor);
        }

        System.out.println("==================");

        //获得指定的构造器
        Constructor constructor = cls.getConstructor(String.class);
        System.out.println(constructor);

        System.out.println("==================");

        //获得非公开权限的构造器
        constructor=cls.getDeclaredConstructor(int.class);
        System.out.println(constructor);

    }

}
public com.senxu.Animal(java.lang.String)
public com.senxu.Animal()
==================
private com.senxu.Animal(int)
public com.senxu.Animal(java.lang.String)
public com.senxu.Animal()
==================
public com.senxu.Animal(java.lang.String)
==================
private com.senxu.Animal(int)

 

(2) Instantiate the object

According to the Class object, use newInstance() to create a new instance of the class represented by the Class object or instantiate the object with the constructor.

Note: newInstance() calls the empty structure, and if the empty structure does not exist, an exception InstantiationException is thrown.

package com.senxu;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

public class Reflection4 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        Class cls = Class.forName(classpath);

        //使用newInstance()创建对象 调用空构造
        Object animal = cls.newInstance();
        System.out.println(animal);

        System.out.println("=================");

        //使用构造器实例化对象
        Constructor constructor = cls.getConstructor(String.class);
        Object dog = constructor.newInstance("小狗");
        System.out.println(dog);

    }

}
com.senxu.Animal@154617c
=================
com.senxu.Animal@a14482

3. Get the properties and methods of any class

(1) attributes

package com.senxu;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;

public class Reflection5 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();

        Class cls = Class.forName(classpath);
        //获得公共的属性
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            
            System.out.println(field);

        }

        System.out.println("=================");

        //获取全部属性
        fields = cls.getDeclaredFields();
        for (Field field : fields) {
      
            System.out.println(field);

        }

    }

}
public java.lang.String com.senxu.Animal.name
public java.lang.String com.senxu.Animal.type
=================
public java.lang.String com.senxu.Animal.name
public java.lang.String com.senxu.Animal.type
private int com.senxu.Animal.num

 

(2) method

package com.senxu;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Reflection6 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();

        Class cls = Class.forName(classpath);

        //获取类自身的全部方法
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println("=====================================================");

        //获得类的所有共有方法,包括自身,从基类继承的,从接口实现的所有public方法
        methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

    }

}
public void com.senxu.Animal.hi()
=====================================================
public void com.senxu.Animal.hi()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

4. Call the properties and methods of any object

(1) Get the properties of the modified object

        The get() method is used for acquisition, and the set() method is used for modification.

package com.senxu;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;

public class Reflection7 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        String typeName = properties.get("varType").toString();

        Class cls = Class.forName(classpath);
        Object animal = cls.newInstance();

        //获取修改对象的属性
        Field type = cls.getDeclaredField(typeName);
        Object o = type.get(animal);
        System.out.println(o);
        type.set(animal,"小猫");
        o=type.get(animal);
        System.out.println(o);

    }

}
小狗
小猫

(2) Call the method of the object

  • Calling an ordinary method on an object

        Use Method.invoke() to pass in the instance and parameters to call.

  • Calling a static method on an object

        Because it is a static method, invoke() does not need to pass in parameters, that is, pass in null calls.

package com.senxu;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Reflection8 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        String methodName = properties.get("method").toString();
        String methodHello = properties.get("methodHello").toString();

        Class cls = Class.forName(classpath);
        Object animal = cls.newInstance();
        Method method1 = cls.getMethod(methodName);
        Method method2 = cls.getMethod(methodHello);
        //调用对象的普通方法
        method1.invoke(animal);
        //调用对象的静态方法
        method2.invoke(null);

    }

}
汪汪汪
你好

5. Generate dynamic proxy

Dynamic creation and use of objects can be realized by modifying the configuration file without modifying the source code.

3. Advantages, disadvantages and optimization of the reflection mechanism

1. Advantages and disadvantages of reflection

(1) Advantages

        Reflection improves program flexibility and scalability, reduces coupling, and improves self-adaptability. It can dynamically create and use objects (that is, the underlying core of the framework), and is flexible to use. It can be said that without the reflection mechanism, the framework technology loses the underlying support.

(2) Disadvantages

  • Performance issues: Using reflection is interpreted execution, which is much slower than direct code when used for fields and methods.
  • Using reflection can obscure the internal logic of the program: programmers want to see the logic of the program in the source code, and reflection bypasses the technology of the source code, thus causing maintenance problems. Reflective code is more complex than the corresponding direct code.

(3) Applicable scenarios of the reflection mechanism

It is mainly used in system frameworks that require high flexibility and scalability, and is not recommended for ordinary programs.

2. Reflective call optimization

(1) Comparison of traditional methods and reflection calls before reflection call optimization

package com.senxu;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Reflection2 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {

        test1();
        test2();

    }

    public static void test1(){

        Animal animal = new Animal();
        long start = System.currentTimeMillis();
        for (int i=0; i<100000000; i++){
            animal.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法来调用hi耗时=" + (end-start));

    }

    public static void test2() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        String methodName = properties.get("method").toString();

        Class cls = Class.forName(classpath);
        Object animal = cls.newInstance();
        Method method = cls.getMethod(methodName);

        long start = System.currentTimeMillis();
        for (int i=0; i<100000000; i++){
            method.invoke(animal);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射调用hi耗时=" + (end-start));

    }

}
传统方法来调用hi耗时=30
反射调用hi耗时=3092

(2) Reflective call optimization - turn off access check

  • Method, Field, and Constructor objects all have setAccessible() methods
  • The function of setAccessible() is to enable and disable the switch of access security check
  • The value of the parameter is true, which means that the reflected object cancels the access check when it is used, improving the efficiency of reflection. A parameter value of false means that the reflected object performs access checks

(3) After the reflection call is optimized, the comparison between the traditional method and the reflection call

package com.senxu;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Reflection2 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {

        test1();
        test2();
        test3();

    }

    public static void test1(){

        Animal animal = new Animal();
        long start = System.currentTimeMillis();
        for (int i=0; i<100000000; i++){
            animal.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法来调用hi耗时=" + (end-start));

    }

    public static void test2() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        String methodName = properties.get("method").toString();

        Class cls = Class.forName(classpath);
        Object animal = cls.newInstance();
        Method method = cls.getMethod(methodName);

        long start = System.currentTimeMillis();
        for (int i=0; i<100000000; i++){
            method.invoke(animal);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制来调用hi耗时=" + (end-start));

    }

    public static void test3() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classpath = properties.get("classpathAnimal").toString();
        String methodName = properties.get("method").toString();

        Class cls = Class.forName(classpath);
        Object animal = cls.newInstance();
        Method method = cls.getMethod(methodName);

        method.setAccessible(true);

        long start = System.currentTimeMillis();
        for (int i=0; i<100000000; i++){
            method.invoke(animal);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射机制优化后来调用hi耗时=" + (end-start));

    }

}
传统方法来调用hi耗时=32
反射机制来调用hi耗时=3114
反射机制优化后来调用hi耗时=753

Guess you like

Origin blog.csdn.net/senxu_/article/details/126338980