Java foundation - can reflection be learned like this? Roommates can get started quickly in the time of hero alliance. Reflection won't hit me (the soul of the framework)

Posted by sean paul on Thu, 23 Dec 2021 11:32:23 +0100

Java foundation - reflection can be learned this way (the soul of the framework)

Write in front

Yesterday, when Xiao Fu was brushing the JDBC source code for the second time, the reflection in the source code secretly came out to give me a stick. In order to deepen the familiarity of reflection in the framework as familiar as abandon, I will learn the basic reflection technology again today. After all, as long as I have deep Kung Fu, I can grind an iron pestle into a needle, Take your time and don't panic ~ your roommate has hit the hero League. You'll have enough time to finish this article. Don't say much, elbow~

Introduction to reflection

What is reflection?

What is reflection?

Java's reflection mechanism is that in the running state, you can know all the properties and methods of any class, for any object. Can call any of its methods and properties at any time. This kind of dynamic access to the relevant information of the class and the method of calling the object is called the reflection mechanism of Java language.

To analyze a class, we must obtain the bytecode file object of the class, that is, XXX from the java program compiled by javac Class file, so we need to get the class type object corresponding to each bytecode first. Then the bottom layer must be called here, and the native method must be indispensable.

Easy to understand

Reflection, to put it bluntly, is to map various components in Java classes into dynamic Java objects

Illustration explanation

When we create an instance of an object (class), we often use the keyword new, which is called

It is called static creation, and the steps of static creation are roughly as shown in the figure above, which is divided into three parts:

1) When we create this instance statically, the JVM will call the underlying method on the local disk to find the corresponding XXX Class file.

2) Find the corresponding XXX Class file will be loaded into the JVM. When the program is running, xxx Class file is read into runtime memory.

3) At this time, if there is no corresponding Class object in the current memory, that is, the only template, the JVM will automatically create a Class object for us to initialize the statically created instance.

As shown in the figure, the normal loading process of the class: the principle of reflection is related to the class object.

Familiar with loading: the origin of class object is to read the class file into memory and create a class object for it.

Basic reflection technology

Development documents of JDK8:

Key understanding

The instance of Class class represents the classes and interfaces in the running Java application, that is, there are many instances in the JVM, and each Class has its corresponding Class object (and eight basic data types)

4 integers: byte, short, int, long

2 floating point types: float, double

1 character type: char

1 boolean

Class has no common construction method. The basic use of reflection technology is as follows

1. Three methods of obtaining Class objects

Three methods to obtain Class objects

  • 1,Object -> getClass();
  • 2. Any data type has a static 'class' attribute
  • 3. It is created through the static method of Class: forName(String className) (the most commonly used)
/**
 * Function description
 * Three methods to get Class objects
 * @author Alascanfu
 * @date 2021/12/21
 */
public class Test {
    public static void main(String[] args) {
        //1. Gets the Class object of the current Class and outputs the name of the Class object
        User user = new User();
        Class<? extends User> userClass1 = user.getClass();
        System.out.println(userClass1.getName());
    
        //2. Through the corresponding class Class can also get the current class object
        Class<? extends User> userClass2 = User.class;
        System.out.println(userClass1 == userClass2);//true
        
        /*3,Call two native underlying methods through the forName method in the Class class
        private static native Class<?> forName0(String name, boolean initialize,
                                               ClassLoader loader,
                                                Class<?> caller)
        And public static native Class in reflection Class <? > getCallerClass(); Two underlying methods are used to get the Class object
        */
        try {
            Class<?> userClass3 = Class.forName("com.alascanfu.ReflectTest.User");
            System.out.println(userClass3 == userClass1);//true
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

be careful

When the program is running, a Class will automatically generate only one Class object in runtime memory.

2. All basic data types have a Type attribute

Class<?> classByte = Byte.TYPE;
Class<?> classShort = Short.TYPE;
Class<?> classInteger = Integer.TYPE;
Class<?> classLong = Long.TYPE;

3. Get the constructor of the class through reflection

User class:

package com.alascanfu.ReflectTest;

public class User {
    private long id ;
    private String name ;
    private String username;
    private String password;
    private String address;
    private String avatar;
    private String permission;
    
    
    User() {
    
    }
    
    protected User(String username){
        this.username = "admin";
    }
    
    private User(long id) {
        this.id = -1L;
    }
    
    public User(long id, String name, String username, String password, String address, String avatar, String permission) {
        this.id = id;
        this.name = name;
        this.username = username;
        this.password = password;
        this.address = address;
        this.avatar = avatar;
        this.permission = permission;
    }
    
    @Override
    public String toString() {
        return "User{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", username='" + username + '\'' +
            ", password='" + password + '\'' +
            ", address='" + address + '\'' +
            ", avatar='" + avatar + '\'' +
            ", permission='" + permission + '\'' +
            '}';
    }
}

There are four ways to call:

public class ConstructorTest {
    public static void main(String[] args) throws Exception{
        //1. Load Class object
        Class<?> userClass = Class.forName("com.alascanfu.ReflectTest.User");
        
    
        //2. Get all public constructor methods
        System.out.println("**********************All public constructors*********************************");
        Constructor[] conArrayPublicCon = userClass.getConstructors();
        for(Constructor c : conArrayPublicCon){
            System.out.println(c);
        }
        //3. Get all construction methods
        System.out.println("**********************All construction methods*********************************");
        Constructor[] conArrayAllCon = userClass.getDeclaredConstructors();
        for(Constructor c : conArrayAllCon){
            System.out.println(c);
        }
        //4. Gets the constructor of the public specified parameter
        System.out.println("*************Gets the public constructor of the specified parameter type from the public constructor******************");
        Constructor<?> constructorPublicDirectParams = userClass.getConstructor(Long.TYPE,String.class,String.class,String.class,String.class,String.class,String.class);
        System.out.println(constructorPublicDirectParams);
    
        //5. Gets all construction methods with specified parameters
        System.out.println("************Gets the constructor of the specified parameter type from all constructors***********************");
        Constructor<?> constructorAllDirectParams = userClass.getDeclaredConstructor(null);
        System.out.println(constructorAllDirectParams);
    }
}

4. Calling construction methods through reflection

The process of creating an instance after obtaining the constructor through the Class object, that is, we often call the construction method through reflection

Code implementation:

//6. Create an instance by the construction method obtained above
        System.out.println("********************Create an instance by the construction method obtained above***********************");
        Object obj1 = constructorPublicDirectParams.newInstance(1L,"Alascanfu","admin","123456","CQTGU", "XXX.IMG", "Administrator");
        System.out.println(obj1);
        Object obj2 = constructorAllDirectParams.newInstance();
        System.out.println(obj2);

The above is the continuation of the following 3. Remember to check the context. What is called here is the specified constructor, including the specified public constructor containing all formal parameters and the specified constructor without any parameters.

Output results:

********************Create an instance by the construction method obtained above***********************
User{id=1, name='Alascanfu', username='admin', password='123456', address='CQTGU', avatar='XXX.IMG', permission='Administrator'}
User{id=0, name='null', username='null', password='null', address='null', avatar='null', permission='null'}

5. Calling methods in a class through reflection

The method in the Class can be obtained by using reflection through the Class object, and the method with the specified parameter name can be obtained. After the method is obtained, the corresponding method can also be executed by using the instance created by reflection.

The public Object invoke(Object obj, Object... args) function is used to execute methods. The first parameter is the instance object and the second parameter is the parameter {},

Through method Invoke (instance, args []) to execute the method, but the method contains the permission modifier. Not all methods can be executed directly. Here, the sharp tool setAccessible(true) method to break the access modifier may be used. It will be said later that it is good to understand it here first.

Code implementation:

//7. Calling methods in a class through reflection
        System.out.println("********************Call all public methods in the class through reflection***********************");
        Method[] publicMethods = userClass.getMethods();
        for (Method method :publicMethods){
            System.out.println(method);
        }
    
        System.out.println("********************Call the public method specified in the class through reflection***********************");
        Method setId = userClass.getMethod("setId", long.class);
        Method getId = userClass.getMethod("getId");
        System.out.println(setId.invoke(obj1, 201901094106L));
        System.out.println(getId.invoke(obj1));
    
        System.out.println("********************Call all methods in the class through reflection***********************");
        Method[] declaredMethods = userClass.getDeclaredMethods();
        for (Method method :declaredMethods){
            System.out.println(method);
        }
    
        System.out.println("********************Call the method specified in the class through reflection***********************");
        Method setPassword = userClass.getDeclaredMethod("setPassword", String.class);
        Method getPassword = userClass.getDeclaredMethod("getPassword");
        setPassword.setAccessible(true);
        getPassword.setAccessible(true);
        System.out.println(setPassword.invoke(obj1, "2021-12-22"));
        System.out.println(getPassword.invoke(obj1));

6. Calling properties in a class through reflection

The Class object is used to call the attributes in the Class through reflection technology, and the attributes can also be modified accordingly

There is also the magical ability to break the permission modifier

The code is as follows:

/**
          *  8,Calling properties through reflection
          *  public int age = 18;
          *  public String sex = "unknown";
         */
        System.out.println("********************Call all public properties in the class through reflection***********************");
        Field[] publicFields = userClass.getFields();
        for (Field field:publicFields){
            System.out.println(field);
        }
        
        System.out.println("********************Call the specified public property in the class through reflection***********************");
        Field age = userClass.getField("age");
        age.set(obj1,21);
        System.out.println(obj1);
    
        System.out.println("********************Call all properties in the class through reflection***********************");
        Field[] allFields = userClass.getDeclaredFields();
        for (Field field:allFields){
            System.out.println(field);
        }
    
        System.out.println("********************Call the specified property in all properties in the class through reflection***********************");
        Field password = userClass.getDeclaredField("password");
        password.setAccessible(true);
        password.set(obj1,"123456");
        System.out.println(obj1);

7. Break the permission modifier, which is the horror of reflection. setAccessible(true)

In Java, access control characters can be used to protect access to classes, variables, methods, and constructor methods. Java supports four different access rights.

  • Default (i.e. default, write nothing): it is visible in the same package without any modifiers. Use objects: classes, interfaces, variables and methods.

  • private: visible in the same class. Using objects: variables, methods. Note: you cannot decorate classes (external classes)

  • public: visible to all classes. Using objects: classes, interfaces, variables, methods

  • protected: visible to classes and all subclasses in the same package. Using objects: variables, methods. Note: you cannot decorate classes (external classes).

If we want to execute the non-public method or obtain the non-public constructor after obtaining the non-public method through reflection, such as the source of all evil in singleton mode - the problem of reflection creation is related to setAccessible(true).

The constructors, methods and properties obtained by using class objects through reflection technology can be modified and obtained by breaking the access control character through setAccessible(true). If they are not obtained, the JVM will report an IllegalAccessException:

Exception in thread "main" java.lang.IllegalAccessException: Class com.alascanfu.ReflectTest.ConstructorTest can not access a member of class com.alascanfu.ReflectTest.User with modifiers "private"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Field.set(Field.java:761)
	at com.alascanfu.ReflectTest.ConstructorTest.main(ConstructorTest.java:94)

Later, under the topic of high concurrency programming in JUC, the single instance mode will be mentioned again when it comes to JMM (Java Memory Model) and Volatile (visibility, not supporting atomicity, and prohibiting instruction rearrangement). Let's learn together later~

8. Running configuration file through reflection technology -- Application of JDBC

public class JDBCUtils {
    public static Connection getConnection() throws Exception{
        //1. Load configuration file
        InputStream resourceAsStream = JDBCUtils.class
            .getClassLoader()
            .getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);
        
        //2. Read configuration information
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driverClass = properties.getProperty("driverClass");
        
        //3. Load drive
        Class.forName(driverClass);
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;
    }
    
    public static void main(String[] args) {
        Connection connection = null;
        try {
            connection = JDBCUtils.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(connection);
    }
}

jdbc.properties is placed under the src project directory. Students who have studied JDBC should know it. I won't talk about it in detail here.

External configuration file JDBC properties

user=root
password=123456
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

Console results:

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
com.mysql.cj.jdbc.ConnectionImpl@5d740a0f

Write it at the back

Today, my roommate spent a lot of time in the hero League to summarize the Java foundation - the use of reflection

To be honest, reflection will be used in many underlying frameworks. If you don't use the most basic reflection,

Many of the underlying source code can't be read, let alone understand the principle.

Finally, we must remember to practice. If we don't practice, we will learn in vain!

I also firmly believe that this easy to understand article can also be recognized by you~

Come on, the foundation is not strong, the earth is shaking, we must have a good look, oh, a game time is enough.

last
Make progress every day and harvest every day
May you succeed in your career and learn
If you feel good, don't forget to click three times~

Topics: Java Back-end reflection