What is reflection

1. First sight reflex

When I first started learning reflection, I was confused. It was really “Abstract mom opens the door to abstract – abstraction is dead.”

Why do I need to get a Class object to create an object? Wouldn’t that kill a dead horse? Wouldn’t it be easier if I just new it?

What are the properties and methods of a program’s run-time fetch class? Usually is the program compile error then modify the code, why should I consider the state of the program run?

I usually development also can’t use, learn this thing have what use?

After learning about annotations, Spring, SpringMVC, etc., reflection is everywhere.

2. The JVM to load classes

We write Java programs that run in the JVM, so to learn reflection, we first need to understand how the JVM loads classes.

1. The.java files we write are called source code.

2. We write a main method in a class, and then click the IDEA run button. When the JVM runs, it triggers the JDK javac instruction to compile the source code into a.class file, which is also called a bytecode file.

3. The JVM’s classloader (you can think of it as a tool) gets the binary stream of a class by its fully qualified name and loads the class file into the JVM’s methods section.

4. When the classloader loads a.class file into the method area, it generates a unique class object in the heap that contains the class’s member variables, constructors, and member methods.

5. This Class object creates an object instance corresponding to the Class.

So ostensibly you’re creating an object, but when the JVM runs the program, what really helps you create the object is the Class object of that Class.

In other words, reflection is basically the JVM encapsulating all the classes you create into a single Class object when you run your program. This Class object contains attributes, constructors, and member methods. You get the Class object, you get those three things.

When you get the reflected Class property, you can get the property name of the object, the property category, the property value, and you can also set the value for the property.

You get the Class constructor after reflection, and you create the object.

After you get the reflection member method, you can execute that method.

3. The concept of reflection

JAVA reflection mechanism is in the program running state, for any class, can know all the attributes and methods of that class; For any object, you can call any of its methods and properties; This ability to dynamically retrieve information and invoke object methods is called the Reflection mechanism of the Java language.

Now that you know how the JVM loads classes, you should have a better understanding of the concept of reflection.

Reflection: THE JVM runs a program –>.java files –>.class files –> class objects –> creates an object instance and operates on its properties and methods

I’m going to talk about related classes and common methods in reflection.

2. Class object

Get the Class object

Create a User class:

public class User {
    private  String name = "Do you know, Sir?";
    public String sex = "Male";

    public User(a) {}public User(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public void eat(a){
        System.out.println("People want to eat!");
    }

    private void run(a){
        System.out.println("People want to run!);
    }

    public String getName(a) {
        return name;
    }

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

    public String getSex(a) {
        return sex;
    }

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

There are three ways to get a Class object:

1. Class. ForName (” Class name “)

Class name: package name + class name

Class userClass = Class.forName("com.xxl.model.User");
Copy the code

2. The name of the class. The class

Class userClass = User.class;
Copy the code

3. Object. GetClass ()

User user = new User();
Class userClass = user.getClass();
Copy the code

Although there are three ways to get a Class object, we generally use the first method above.

Once we have the Class object, we can manipulate the methods associated with it.

3. Obtain the class name

1. Obtain the complete class name: package name + class name

getName()

Class userClass = Class.forName("com.xxl.model.User");
String name = userClass.getName();
System.out.println(name);
Copy the code

Print result:

2. Get simple class name: not including package name

getSimpleName()

Class userClass = Class.forName("com.xxl.model.User");
String simpleName = userClass.getSimpleName();
System.out.println(simpleName);
Copy the code

Print result:

4. The attribute

4.1 Obtaining Attributes

1. Get all public attributes: public modifier

getFields()

Class userClass = Class.forName("com.xxl.model.User");
Field[] fields = userClass.getFields();
for (Field field : fields) {
    System.out.println(field);
}
Copy the code

Print result:

2. Obtain a single public attribute

GetField (” Attribute name “)

Class userClass = Class.forName("com.xxl.model.User");
Field field = userClass.getField("sex");
System.out.println(field);
Copy the code

Print result:

3. Get all attributes: public + private

getDeclaredFields()

Class userClass = Class.forName("com.xxl.model.User");
Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field);
}
Copy the code

Print result:

4. Get a single attribute: public or private

GetDeclaredField (” property name “)

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
Field sexField = userClass.getDeclaredField("sex");
System.out.println(nameField);
System.out.println(sexField);
Copy the code

Print result:

4.2 Operation Attributes

1. Obtain the attribute name

getName()

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
System.out.println(nameField.getName());
Copy the code

Print result:

2. Obtain the attribute type

getType()

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
System.out.println(nameField.getType());
Copy the code

Print result:

3. Obtain the attribute value

get(object)

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("sex");
User user = new User();
System.out.println(nameField.get(user));
Copy the code

Print result:

Note: The value of a private property cannot be obtained directly by reflection, but can be obtained by modifying the access entry.

Set to allow access to private properties:

field.setAccessible(true);
Copy the code

Such as:

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);
User user = new User();
System.out.println(nameField.get(user));
Copy the code

Printing method:

4. Set the property value

Set (object,” attribute value “)

Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);
User user = new User();
nameField.set(user,"Zhang Wuji");
System.out.println(nameField.get(user));
Copy the code

Print result:

5. Construction method

1. Get all public constructors

getConstructors()

Class userClass = Class.forName("com.xxl.model.User");
Constructor[] constructors = userClass.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}
Copy the code

Print result:

2. Obtain the constructor that matches the parameter type

GetConstructor (parameter type)

Class userClass = Class.forName("com.xxl.model.User");
Constructor constructor = userClass.getConstructor(String.class, String.class);
System.out.println(constructor);
Copy the code

Print result:

6. Membership method

6.1 Obtaining member Methods

1. Get all public methods

getMethods()

Class userClass = Class.forName("com.xxl.model.User");
Method[] methods = userClass.getMethods();
for (Method method : methods) {
    System.out.println(method);
}
Copy the code

Print result:

We find that in addition to the custom public methods, the print results also have public methods inherited from the Object class.

2. Get some public method

GetMethod (” method name “, parameter type)

Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getMethod("setName", String.class);
System.out.println(method);
Copy the code

Print result:

3. Get all methods: public + private

getDeclaredMethods()

Class userClass = Class.forName("com.xxl.model.User");
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method method : declaredMethods) {
    System.out.println(method);
}
Copy the code

Print result:

4. Get a method: public or private

GetDeclaredMethod (” method name “, parameter type)

Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getDeclaredMethod("run");
System.out.println(method);
Copy the code

Print result:

6.2 Implementing member methods

Invoke (object,” method parameter “)

Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getDeclaredMethod("eat");
User user = new User();
method.invoke(user);
Copy the code

Print result:

Note: Private member methods cannot be executed directly through reflection, but they can be set to allow access.

Set to allow private methods to execute:

method.setAccessible(true);
Copy the code

7. Note

1. Determine when a class or method contains an annotation

IsAnnotationPresent (annotation name.class)Copy the code

Such as:

Class userClass = Class.forName("com.xxl.model.User");
if(userClass.isAnnotationPresent(Component.class)){
    Component annotation = (Component)userClass.getAnnotation(Component.class);
    String value = annotation.value();
    System.out.println(value);
};
Copy the code

2. Get annotations

GetAnnotation (annotation name.class)Copy the code

Such as:

Class userClass = Class.forName("com.xxl.model.User");
// Get the annotation on the class
Annotation annotation1 = userClass.getAnnotation(Component.class);
Method method = userClass.getMethod("eat");
// Get some annotation on the method
Annotation annotation2 = userClass.getAnnotation(Component.class);
Copy the code

8. Create an instance of the class

1. Instantiate objects through Class

Class.newInstance()

Class userClass = Class.forName("com.xxl.model.User");
User user = (User)userClass.newInstance();
System.out.println("Name:"+user.getName()+"Gender:+user.getSex());
Copy the code

Print result:

2. Instantiate objects using constructors

Constructor.newinstance (parameter values)

Class userClass = Class.forName("com.xxl.model.User");
Constructor constructor = userClass.getConstructor(String.class, String.class);
User user = (User)constructor.newInstance\("Li Shiqing"."Female"\);
System.out.println("Name:"+user.getName()+"Gender:+user.getSex());
Copy the code

Print result:

9. Reflection cases

One day, the technical director said to Zhang SAN, “Zhang SAN, I heard that you have learned reflection recently. Then you design an object factory class to show me.

Zhang SAN thought: “Oh, fast New Year, leadership this is to give me a raise. I will do well this time.”

Five minutes later, Joe submitted the code:

public class ObjectFactory {
    
    public static User getUser(a) {
        
        User user = null;
        try {
            Class userClass = Class.forName("com.xxl.model.User");
            user = (User) userClass.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return user;
    }

    public static UserService getUserService(a) {
        UserService userService = null;
        try {
            Class userClass = Class.forName("com.xxl.service.impl.UserServiceImpl");
            userService = (UserService) userClass.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        returnuserService; }}Copy the code

The TECHNICAL director glanced at the code and said to Sam, “There are two problems with your factory class.”

1. There is a lot of redundancy in code. If you have 10,000 classes, do you have to write 10,000 static methods?

2. Code coupling is too high. If the package path of these classes changes, will you have a problem getting the Class object using forName ()? You u have to manually change the code one by one, then compile, package, and deploy it. Doesn’t it bother you?

“Think for a moment if you can just design a static class that uses reflection to create objects by passing parameters that are less decouple from the factory class. By the way, look at how JDBC gets database connection parameters.”

Zhang SAN a listen: “worthy of the director ah, inspired ah! Give me 10 minutes.”

Ten minutes later, Joe submitted the code again:

object.properties

user=com.xxl.model.User
userService=com.xxl.service.impl.UserServiceImpl
Copy the code

ObjectFactory

public class ObjectFactory {

    private static Properties objectProperty = new Properties();

    Static methods are executed at class initialization and only once
    static{
        try {
            InputStream inputStream = ObjectFactory.class.getResourceAsStream("/object.properties");
            objectProperty.load(inputStream);
            inputStream.close();
        } catch(IOException e) { e.printStackTrace(); }}public static Object getObject(String key){
        Object object = null;
        try {
            Class objectClass = Class.forName(objectProperty.getProperty(key));
            object = objectClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        returnobject; }}Copy the code

Test method:

@Test
  void testObject(a) {
      User user = (User)ObjectFactory.getObject("user");
      UserService userService = (UserService)ObjectFactory.getObject("userService");
      System.out.println(user);
      System.out.println(userService);
  }
Copy the code

Execution Result:

The director nodded repeatedly and said to Zhang SAN with a smile, “Using the properties file to store the fully qualified name of the class reduces the coupling degree of the code, and using reflection to create objects by passing parameters reduces the redundancy of the code. This change is ok.”

“Ok, tonight is the launch of the project, let’s go to dinner, later I have to fix the bug.”

Joe: “… Good director.”

10. The Role of Reflection

We’ve all heard of the use of reflection when designing frameworks. Spring’s IOC uses factory patterns and reflection to create objects, and the underlying BeanUtils uses reflection to copy properties. So reflection is everywhere.

Although we rarely use reflection in our daily development, we need to understand how reflection works because it helps us understand how framework design works.