Java - print classes through reflection

Keywords: Java

I've been working for some time. I think it's time to review some basic knowledge of Java, so I wrote this article. In the ordinary development process, the front end writes more, and the back end can't forget!

1, Case departure

Prepare a template class first:

public class User {
    public int id;
    private String name;

    public User(String name, int id) {
        this.id = id;
        this.name = name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

2. Start reflection

import java.lang.reflect.*;

public class Test {
    public static final String LINE = "\n";
    public static final String SPACE = "    ";

    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName("com.User");
        // Class<?> c = Test.class.getClassLoader().loadClass("com.User");
        StringBuilder sb = new StringBuilder();
        // Print package, class name
        String packageName = c.getPackage().getName();
        sb.append("package " + packageName + ";" + LINE);
        sb.append(LINE);
        sb.append("public class " + c.getSimpleName() + "{" + LINE);
        // Print member variables
        Field[] declaredFields = c.getDeclaredFields();
        for (Field field : declaredFields) {
            // Field.getModifiers() returns a numeric value of type int, which is used to identify public, static and other identifiers
            String fieldModifier = Modifier.toString(field.getModifiers());
            // Gets the brief name of the property type
            String typeName = field.getType().getSimpleName();
            // The name of the property
            String fieldName = field.getName();
            sb.append(SPACE + fieldModifier + " " + typeName + " " + fieldName + ";" + LINE);
        }
        sb.append(LINE);
        // Print structure
        Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
        for (Constructor<?> constructor : declaredConstructors) {
            // Identifier of the constructor
            String constructorModifier = Modifier.toString(constructor.getModifiers());
            sb.append(SPACE + constructorModifier + " " + c.getSimpleName() + " " + "(");
            // Print constructor parameters
            printParam(sb, constructor.getParameterTypes());
        }
        // Printing method
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            // Identifier of the method
            String methodModifier = Modifier.toString(method.getModifiers());
            // Method return type
            String returnTypeName = method.getReturnType().getSimpleName();
            // Method name
            String methodName = method.getName();
            sb.append(SPACE + methodModifier + " " + returnTypeName + " " + methodName + "(");
            printParam(sb, method.getParameterTypes());
        }

        sb.append("}");
        System.out.println(sb.toString());
    }

    private static void printParam(StringBuilder sb, Class<?>[] parameterTypes2) {
        Class<?>[] parameterTypes = parameterTypes2;
        for (int i = 0; i < parameterTypes.length; i++) {
            // Type of parameter
            String simpleName = parameterTypes[i].getSimpleName();
            if (i == 0) {
                sb.append(simpleName + " args");
            } else {
                sb.append(", " + simpleName + " args");
            }
        }
        sb.append(") {" + LINE);
        sb.append(SPACE + "}" + LINE);
        sb.append(LINE);
    }
}

The final results are as follows:

2, Analysis of reflection method

2.1 reflection mode

In the code, we can find that there are two basic reflections:

  • Class.forName()
  • getClassLoader().loadClass()

First, add static block code in the template class:

Let's run the code of two reflection modes:
forName:

getClassLoader:

The conclusions are as follows:

Initialization: objects reflected through forName will be initialized (static code will be executed), while objects reflected through getClassLoader will not be initialized.

2.2 printing of modifiers

If we want to print the modifiers of methods and properties, we should get them through the Modifier class. Look at this line of code:

String fieldModifier = Modifier.toString(field.getModifiers());

Take a look at the source code of Modifier.toString:

public static String toString(int mod) {
    StringBuilder sb = new StringBuilder();
    int len;

    if ((mod & PUBLIC) != 0)        sb.append("public ");
    if ((mod & PROTECTED) != 0)     sb.append("protected ");
    if ((mod & PRIVATE) != 0)       sb.append("private ");

    /* Canonical order */
    if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
    if ((mod & STATIC) != 0)        sb.append("static ");
    if ((mod & FINAL) != 0)         sb.append("final ");
    if ((mod & TRANSIENT) != 0)     sb.append("transient ");
    if ((mod & VOLATILE) != 0)      sb.append("volatile ");
    if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
    if ((mod & NATIVE) != 0)        sb.append("native ");
    if ((mod & STRICT) != 0)        sb.append("strictfp ");
    if ((mod & INTERFACE) != 0)     sb.append("interface ");

    if ((len = sb.length()) > 0)    /* trim trailing space */
        return sb.toString().substring(0, len-1);
    return "";
}

Obviously, it is mapped and returned by the type of language modifier (int type).
There are three places in the case code that support obtaining modifier types:

  1. field.getModifiers(): field modifiers.
  2. constructor.getModifiers(): construct modifiers.
  3. method.getModifiers(): modifier of the method.

2.3 difference between getdeclaredxxx and getxxx

Take Field as an example:

Field[] declaredFields = c.getDeclaredFields();
Field[] fields = c.getFields();

The cases are as follows:
1. Create a new Parent class:

public class Parent {
    public String parentAddress;
    private Integer Number;
}

2. Let the User class inherit the Parent class

3. Test 1: getdeclaraedfields print member variables:

4. Test 2: getFields print member variables:

The differences are as follows:

Comparison contentgetDeclaredFieldsgetFields
The scope of the class being acted onCurrent class onlyYou can also include parent classes
Modifier range of actionYou can get public and non-public typesOnly relevant values of public type can be obtained

2.4 what is the difference between getsimplename and getName

Take this line of code as an example:

String typeName = field.getType().getSimpleName();

If I change getSimpleName to getName, see how the output will be different:

It can be found that gatName outputs the full name of the type, and the corresponding getSimpleName returns the type name as the name suggests.

For other related attributes and API s, the code comments are written in detail, so I won't expand the introduction.

Posted by zachatk1 on Sun, 12 Sep 2021 00:26:09 -0700