Backend Development 21 min read

Understanding Java Reflection: Concepts, API Details, and Practical Code Examples

This article explains Java's reflection mechanism, covering how to obtain Class objects, inspect constructors, fields, and methods, invoke them dynamically, run main methods via reflection, use configuration files for flexible execution, and bypass generic type checks with reflective calls.

Java Captain
Java Captain
Java Captain
Understanding Java Reflection: Concepts, API Details, and Practical Code Examples

Reflection Is the Soul of Framework Design

Reflection allows a program to inspect and manipulate classes, methods, fields, and constructors at runtime, turning class components into Java objects that can be examined and invoked dynamically.

1. Overview of Reflection

Java's reflection mechanism enables you to discover all attributes and methods of any class and invoke them on any object during execution.

2. Class API Details (Java 1.7)

The Class object represents a loaded .class file. It is created by the JVM when a class is loaded.

2.1 Obtaining a Class Object

Three common ways to get a Class object:

Object instance: obj.getClass()

Static .class literal: MyClass.class

Dynamic loading: Class.forName("com.example.MyClass")

3. Using Reflection – Constructor Examples (Student class)

First, define a simple Student class with multiple constructors.

package fanshe;
public class Student {
    public Student(String str) { System.out.println("(default) constructor s = " + str); }
    public Student() { System.out.println("Public no‑arg constructor executed"); }
    public Student(char name) { System.out.println("Name: " + name); }
    public Student(String name, int age) { System.out.println("Name: " + name + ", Age: " + age); }
    protected Student(boolean n) { System.out.println("Protected constructor n = " + n); }
    private Student(int age) { System.out.println("Private constructor Age = " + age); }
}

Test class to demonstrate constructor reflection:

package fanshe;
import java.lang.reflect.Constructor;
public class Constructors {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("fanshe.Student");
        // All public constructors
        for (Constructor c : clazz.getConstructors()) System.out.println(c);
        // All constructors (including private, protected)
        for (Constructor c : clazz.getDeclaredConstructors()) System.out.println(c);
        // Obtain and invoke a public no‑arg constructor
        Constructor con = clazz.getConstructor();
        Object obj = con.newInstance();
        // Obtain and invoke a private constructor
        con = clazz.getDeclaredConstructor(char.class);
        con.setAccessible(true);
        obj = con.newInstance('M');
    }
}

4. Accessing Fields via Reflection

Define a Student class with various fields:

package fanshe.field;
public class Student {
    public String name;
    protected int age;
    char sex;
    private String phoneNum;
    @Override public String toString() { return "Student [name="+name+", age="+age+", sex="+sex+", phoneNum="+phoneNum+"]"; }
}

Reflection test to read and modify fields:

package fanshe.field;
import java.lang.reflect.Field;
public class Fields {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("fanshe.field.Student");
        // Public fields
        for (Field f : clazz.getFields()) System.out.println(f);
        // All fields
        for (Field f : clazz.getDeclaredFields()) System.out.println(f);
        // Modify public field "name"
        Field f = clazz.getField("name");
        Object obj = clazz.getConstructor().newInstance();
        f.set(obj, "Andy Lau");
        System.out.println(((fanshe.field.Student)obj).name);
        // Modify private field "phoneNum"
        f = clazz.getDeclaredField("phoneNum");
        f.setAccessible(true);
        f.set(obj, "18888889999");
        System.out.println(((fanshe.field.Student)obj).toString());
    }
}

5. Invoking Methods via Reflection

Define a Student class with several methods of different visibility:

package fanshe.method;
public class Student {
    public void show1(String s) { System.out.println("Public show1: " + s); }
    protected void show2() { System.out.println("Protected show2"); }
    void show3() { System.out.println("Package‑private show3"); }
    private String show4(int age) { System.out.println("Private show4 age=" + age); return "abcd"; }
}

Reflection test to list and invoke methods:

package fanshe.method;
import java.lang.reflect.Method;
public class MethodClass {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("fanshe.method.Student");
        // All public methods (including inherited)
        for (Method m : clazz.getMethods()) System.out.println(m);
        // All declared methods
        for (Method m : clazz.getDeclaredMethods()) System.out.println(m);
        // Invoke public method show1
        Method m = clazz.getMethod("show1", String.class);
        Object obj = clazz.getConstructor().newInstance();
        m.invoke(obj, "Andy Lau");
        // Invoke private method show4
        m = clazz.getDeclaredMethod("show4", int.class);
        m.setAccessible(true);
        Object result = m.invoke(obj, 20);
        System.out.println("Return value: " + result);
    }
}

6. Reflectively Invoking a Main Method

Student class with a static main method:

package fanshe.main;
public class Student {
    public static void main(String[] args) { System.out.println("main method executed..."); }
}

Reflection test to call that main :

package fanshe.main;
import java.lang.reflect.Method;
public class Main {
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName("fanshe.main.Student");
            Method methodMain = clazz.getMethod("main", String[].class);
            methodMain.invoke(null, (Object) new String[]{"a","b","c"});
        } catch (Exception e) { e.printStackTrace(); }
    }
}

7. Configuration‑Driven Reflection

Using a properties file ( pro.txt ) to specify class and method names, allowing the program to run new code without recompilation.

# pro.txt
className=cn.fanshe.Student
methodName=show

Demo that reads the configuration and invokes the specified method:

import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
public class Demo {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName(getValue("className"));
        Method m = clazz.getMethod(getValue("methodName"));
        m.invoke(clazz.getConstructor().newInstance());
    }
    private static String getValue(String key) throws Exception {
        Properties p = new Properties();
        try (FileReader in = new FileReader("pro.txt")) { p.load(in); }
        return p.getProperty(key);
    }
}

Changing the properties to point to Student2.show2 runs the new method without code changes.

8. Bypassing Generic Type Checks with Reflection

Generics are erased at runtime, so reflective calls can insert values of any type into a generic collection.

import java.lang.reflect.Method;
import java.util.ArrayList;
public class Demo {
    public static void main(String[] args) throws Exception {
        ArrayList
list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        Method m = list.getClass().getMethod("add", Object.class);
        m.invoke(list, 100); // inserts Integer into List
for (Object o : list) System.out.println(o);
    }
}

Output demonstrates that the integer value is stored alongside strings.

Conclusion

Reflection provides powerful capabilities for dynamic class inspection, object creation, field manipulation, method invocation, configuration‑driven execution, and even generic type circumvention, making it a core tool for many Java frameworks and advanced programming techniques.

JavaReflectionclassConstructormethod
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.