# What is "Reflection"?

In Java, reflection is a feature that allows the examination and manipulation of classes, interfaces, fields, methods, and their properties at runtime. It provides a way to inspect and modify classes, interfaces, fields, methods, etc., irrespective of their access level.

Reflection in Java allows you to:

  1. Inspect classes: You can obtain information about classes like their constructors, methods, fields, and annotations.
  2. Instantiate objects: You can create new instances of classes, even if the names of the classes are not known until runtime.
  3. Invoke methods: Reflection allows invoking methods on objects dynamically, even if the method names are not known until runtime.
  4. Access and modify fields: You can access and modify the fields of a class, regardless of their access level (e.g., private, protected, public).

​ This description is from ChatGPT, but we can only understand it deeply after we figure out its implementation.

​ As we know, Java is a kind of compiled programming language. When we finish our code, we need to compile the code into "class" files, after that, the JVM can execute the class files to transform our code into binary files, so the devices can understand our code.

​ So, every object in Java runtime is the object of class, and Java runtime keeps only one object of Class for all objects from the same class file. What we should figure out is that "Class" is different from "class", "Class" means "Class.java" but "class" is one kind of compiled file, and the object of class is created by "Class".

​ Let's check Class.java, there are some important properties and methods...

private Class(ClassLoader loader) {
    // Initialize final field for classLoader.  The initialization value of non-null
    // prevents future JIT optimizations from assuming this final field is null.
    classLoader = loader;
}

public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

public T newInstance()
    throws InstantiationException, IllegalAccessException
{
    if (System.getSecurityManager() != null) {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
    }

    // NOTE: the following code may not be strictly correct under
    // the current Java memory model.

    // Constructor lookup
    if (cachedConstructor == null) {
        if (this == Class.class) {
            throw new IllegalAccessException(
                "Can not call newInstance() on the Class for java.lang.Class"
            );
        }
        try {
            Class<?>[] empty = {};
            final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
            // Disable accessibility checks on the constructor
            // since we have to do the security check here anyway
            // (the stack depth is wrong for the Constructor's
            // security check to work)
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<Void>() {
                    public Void run() {
                            c.setAccessible(true);
                            return null;
                        }
                    });
            cachedConstructor = c;
        } catch (NoSuchMethodException e) {
            throw (InstantiationException)
                new InstantiationException(getName()).initCause(e);
        }
    }
    Constructor<T> tmpConstructor = cachedConstructor;
    // Security check (same as in java.lang.reflect.Constructor)
    int modifiers = tmpConstructor.getModifiers();
    if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
        Class<?> caller = Reflection.getCallerClass();
        if (newInstanceCallerCache != caller) {
            Reflection.ensureMemberAccess(caller, this, null, modifiers);
            newInstanceCallerCache = caller;
        }
    }
    // Run constructor
    try {
        return tmpConstructor.newInstance((Object[])null);
    } catch (InvocationTargetException e) {
        Unsafe.getUnsafe().throwException(e.getTargetException());
        // Not reached
        return null;
    }
}

public Field getDeclaredField(String name)
    throws NoSuchFieldException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Field field = searchFields(privateGetDeclaredFields(false), name);
    if (field == null) {
        throw new NoSuchFieldException(name);
    }
    return field;
}

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
    if (method == null) {
        throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

​ So we can find some important points below:

	1. Classloader is a final field, so there is only one classloader in the JVM;
	1. We can get the Class object through "forName" method by passing the class name;
	1. Class object using "newInstance" method to create new instances of the class represented by itself;
	1. Fields and methods are stored in Class objects, we can easily get them through their name;

​ Then, we found that "Field" and "Method" are in the same package "java.lang.reflect", this package has all files about reflection. Let's go deep into "Field" and "Method" files, and check some important methods;

// set method in Field file
public void set(Object obj, Object value)
    throws IllegalArgumentException, IllegalAccessException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    getFieldAccessor(obj).set(obj, value);
}

// invoke method in Method file
public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

​ So it is very obvious, we can change the values of the fields if we want and we can invoke the methods also.

​ Then, why do we need reflection? What reflection can do?

​ I think the main scenario is, that because sometimes the properties and methods are private, we can't directly change the properties and invoke the methods. Reflection is the tool that can help us to change the private properties and invoke the private methods.

​ check the demo below, and run it on your device, thanks for reading.

package com.javademo.reflection;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Description;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

@Description("这是测试父类!")
@ReflectionDemo.FatherInherited("可继承注解!")
class TestFather{
    public Float price;

    @Value("HUAWEI")
    private String brandName;

    protected Float sumPrice;

    public TestFather(){}

    public void testPublic(){}

    private void testPrivate(){}
}

@Description("这是测试类!")
class TestReflection extends TestFather{

    public Float store;

    @Value("11")
    private Number number;

    protected String name;

    public TestReflection(){
        super();
        this.name = "Bruce Lee";
        this.number = 30;
    }

    public void testPublic(){}

    private void testPrivate(String name, Number number){
        this.name = name;
        this.number = number;
        System.out.println("输出name:"+name+",number:"+number.toString());
    }

    public void output(){
        System.out.println("输出name:"+this.name+",number:"+this.number.toString());
    }
}

public class ReflectionDemo {

    //声明一个可继承的自定义注解
    @Inherited //表示此注解可以被子类继承
    @Retention(RetentionPolicy.RUNTIME) //表示此注解可以被通过反射读取
    public @interface FatherInherited{
        String value() default "";
    }

    public TestReflection testReflection = new TestReflection();

    //获取类的class信息
    private void classInfo() throws NoSuchFieldException {
        //获取类的class对象
        Class testReflectionClass = testReflection.getClass();
        //class对象常见的方法:
        //获取类对象所属类的名称
        String className = testReflectionClass.getName();
        System.out.println("类对象所属类的名称:"+className);

        //获取类对象的变量对象
        String fieldClassName = testReflectionClass.getDeclaredField("number").getType().getName();
        System.out.println("类对象的成员变量number所属类的名称:"+fieldClassName);

        //获取类对象以及其父类的public成员变量数组
        String fieldArrayString = Arrays.toString(testReflectionClass.getFields());
        System.out.println("获取类对象以及其父类的public成员变量数组:"+fieldArrayString);

        //获取类对象以及其父类的所有成员变量数组
        String declaredFieldArrayString = Arrays.toString(testReflectionClass.getDeclaredFields());
        System.out.println("获取类对象以及其父类的所有成员变量数组:"+declaredFieldArrayString);

        //类对象以及其父类的所有public方法
        String methodArrayString = Arrays.toString(testReflectionClass.getMethods());
        System.out.println("类对象以及其父类的所有public方法:"+methodArrayString);

        //类对象以及其父类的所有方法
        String declaredMethodArrayString = Arrays.toString(testReflectionClass.getDeclaredMethods());
        System.out.println("类对象以及其父类的所有方法:"+declaredMethodArrayString);

        //类对象的所有注解(包含父类可继承注解),注意不包括成员变量的注解
        String annotationArrayString = Arrays.toString(testReflectionClass.getAnnotations());
        System.out.println("类对象的所有注解(包含继承):"+annotationArrayString);

        //类对象的所有注解(不包含继承),注意不包括成员变量的注解
        String declaredAnnotationArrayString = Arrays.toString(testReflectionClass.getDeclaredAnnotations());
        System.out.println("类对象的所有注解(不包含继承):"+declaredAnnotationArrayString);
    }

    //利用反射对类对象的成员变量进行操作
    private void fieldAction() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, InstantiationException {
        //输出赋值前结果
        System.out.println("Field赋值前的结果:");
        testReflection.output();
        //获取类的class对象
        Class testReflectionClass = Class.forName("com.javademo.reflection.TestReflection");
        //获取Field对象
        Field fieldName = testReflectionClass.getDeclaredField("name");
        Field fieldNum = testReflectionClass.getDeclaredField("number");
        //给Field对象赋值
        fieldName.setAccessible(true); //当成员变量为私有变量时需设置权限为true,public变量不需要
        fieldName.set(testReflection, "李小龙");
        fieldNum.setAccessible(true); //当成员变量为私有变量时需设置权限为true,public变量不需要
        fieldNum.set(testReflection, 25);
        //输出fild的赋值结果
        System.out.println("Field赋值后的结果:");
        testReflection.output();
    }

    //利用反射调用类对象的方法
    private void methodAction() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        //获取类的class对象
        Class testReflectionClass = Class.forName("com.javademo.reflection.TestReflection");
        //获取method对象
        Method method = testReflectionClass.getDeclaredMethod("testPrivate", String.class, Number.class);
        //私有方法需设置权限
        method.setAccessible(true);
        //通过invoke方法调用方法传参
        System.out.println("调用method后结果:");
        method.invoke(testReflection, "小龙", 28);
    }

    public static void main(String[] args) throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        ReflectionDemo reflectionDemo = new ReflectionDemo();
        reflectionDemo.classInfo();
        reflectionDemo.fieldAction();
        reflectionDemo.methodAction();
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
Last update: 10/31/2023, 5:11:25 PM