Fundamentals 7 min read

Understanding Java Reflection: Classes, Methods, Constructors, and Fields

This article explains Java's reflection mechanism, showing how to obtain Class objects, dynamically load classes, and retrieve information about methods, fields, and constructors, accompanied by practical code examples that demonstrate inspecting and invoking members at runtime.

Java Captain
Java Captain
Java Captain
Understanding Java Reflection: Classes, Methods, Constructors, and Fields

Java reflection enables programs to discover and manipulate class metadata—such as methods, fields, and constructors—while the application is running, providing dynamic capabilities beyond static compilation.

Obtaining a Class object can be done in three ways: using the class literal, calling obj.getClass() , or invoking Class.forName("full.class.Name") . Example:

public class User {}
public class ClassTest {
    User u = new User(); // way 1
    Class c1 = User.class; // way 2
    Class c2 = u.getClass(); // way 3
    Class c3 = Class.forName("com.forezp.User"); // dynamic loading
    User user = (User) c1.newInstance();
}

Dynamic class loading is performed with Class.forName() , which loads the class at runtime rather than at compile time.

Retrieving method information involves using Class.getMethods() or Class.getDeclaredMethods() . The following utility prints each method’s return type, name, and parameter types:

public static void printClassInfo(Object object) {
    Class c = object.getClass();
    System.out.println("Class name: " + c.getName());
    Method[] methods = c.getMethods();
    for (Method m : methods) {
        Class ret = m.getReturnType();
        System.out.print(ret.getName() + " " + m.getName() + "(");
        for (Class p : m.getParameterTypes()) {
            System.out.print(p.getName() + ",");
        }
        System.out.println(")");
    }
}

public class ReflectTest {
    public static void main(String[] args) {
        String s = "ss";
        ClassUtil.printClassInfo(s);
    }
}
Class name: java.lang.String boolean equals(java.lang.Object,) java.lang.String toString() int hashCode() …

Accessing field information uses Class.getDeclaredFields() to retrieve all fields, regardless of visibility:

public static void printFieldInfo(Object o) {
    Class c = o.getClass();
    Field[] fields = c.getDeclaredFields();
    for (Field f : fields) {
        System.out.println(f.getType().getName() + " " + f.getName());
    }
}

public class Test {
    public static void main(String[] args) {
        String s = "ss";
        ClassUtil.printFieldInfo(s);
    }
}
[C value int hash long serialVersionUID [Ljava.io.ObjectStreamField; serialPersistentFields java.util.Comparator CASE_INSENSITIVE_ORDER int HASHING_SEED int hash32

Retrieving constructor details is done via Class.getDeclaredConstructors() :

public static void printConstructInfo(Object o) {
    Class c = o.getClass();
    Constructor[] cons = c.getDeclaredConstructors();
    for (Constructor con : cons) {
        System.out.print(con.getName() + "(");
        for (Class p : con.getParameterTypes()) {
            System.out.print(p.getName() + ",");
        }
        System.out.println(")");
    }
}

public class Test {
    public static void main(String[] args) {
        String s = "ss";
        ClassUtil.printConstructInfo(s);
    }
}
java.lang.String([B ,) java.lang.String([B ,int ,int ,) java.lang.String([B ,java.nio.charset.Charset ,) java.lang.String([B ,java.lang.String ,) java.lang.String([B ,int ,int ,java.nio.charset.Charset ,) java.lang.String(int ,int ,[C ,) java.lang.String([C ,boolean ,) java.lang.String(java.lang.StringBuilder ,) java.lang.String(java.lang.StringBuffer ,) …

Method invocation via reflection requires obtaining a Method object and calling invoke() with the target instance and arguments. Example:

class A {
    public void add(int a, int b) { System.out.print(a + b); }
    public void toUpper(String a) { System.out.print(a.toUpperCase()); }
}

public class Test {
    public static void main(String[] args) {
        A a = new A();
        Class c = a.getClass();
        try {
            Method m = c.getMethod("add", int.class, int.class);
            m.invoke(a, 10, 10);
        } catch (Exception e) { e.printStackTrace(); }
    }
}
20

In summary, Java reflection allows runtime inspection of any object's class, creation of instances, access to fields and methods, and dynamic method invocation, forming the basis for advanced techniques such as dynamic proxies and framework development.

JavaReflectionTutorialclassConstructormethodfield
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.