Reflection

Reflection

A school program needs reliable data and clear rules. Reflection inspects types and members while a program runs. It can discover a student’s class name, but direct calls remain clearer when the type is already known.

  1. Understand

    Reflection inspects types and members while a program runs.

  2. Apply

    Trace the Java example, predict its output and explain the result before running it.

  3. Avoid mistakes

    Reflection does not automatically bypass module or access restrictions. Failures often become runtime errors rather than compile-time checks.

Reflection

Reflection in Java is a powerful and somewhat magical feature. It lets your code inspect and manipulate itself or other classes at runtime. Think of it as a way to peek behind the curtain of how Java classes, fields, and methods are structured and to even tweak them dynamically—without knowing their names at compile time.

Why Use Reflection?

  • To create instances of classes dynamically (useful in frameworks and tools)
  • To inspect metadata (like class names, fields, annotations)
  • To invoke methods or access fields that might otherwise be private
  • To write generic code that can operate on any class

Key Classes in the Reflection API

The Java Reflection API is primarily built around classes from the java.lang.reflect package:

  • Class - Represents classes and interfaces
  • Method - Represents class methods
  • Field - Represents class variables
  • Constructor - Represents class constructors

Getting the Class Object

To begin reflection, we first need a Class object. Here's how:

Class<?> clazz1 = MyClass.class;              // Using .class
Class<?> clazz2 = obj.getClass();             // From an instance
Class<?> clazz3 = Class.forName("MyClass");   // By name

Let’s see a complete example.

class MyClass {
    public int x = 42;
    private String secret = "Hidden Message";

    public void show() {
        System.out.println("Hello from MyClass!");
    }
}
public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("MyClass");

        Object obj = clazz.getDeclaredConstructor().newInstance();
        System.out.println("Class name: " + clazz.getName());

        // Access public field
        java.lang.reflect.Field field = clazz.getField("x");
        System.out.println("Value of x: " + field.getInt(obj));
    }
}
Class name: MyClass
Value of x: 42

Accessing Private Fields

Reflection even allows access to private fields—something you can’t do through regular code.

Field secretField = clazz.getDeclaredField("secret");
secretField.setAccessible(true);
String secretValue = (String) secretField.get(obj);
System.out.println("Private field value: " + secretValue);
Private field value: Hidden Message

Listing All Fields and Methods

for (Field f : clazz.getDeclaredFields()) {
    System.out.println("Field: " + f.getName());
}

for (Method m : clazz.getDeclaredMethods()) {
    System.out.println("Method: " + m.getName());
}
Field: x
Field: secret
Method: show

Invoking Methods with Reflection

Method method = clazz.getMethod("show");
method.invoke(obj);
Hello from MyClass!

Creating Instances Dynamically

This technique is heavily used in frameworks like Spring or Hibernate where classes are created on-the-fly.

Class<?> dynamicClass = Class.forName("MyClass");
Object instance = dynamicClass.getDeclaredConstructor().newInstance();

Accessing Constructors

Constructor<?> constructor = clazz.getDeclaredConstructor();
System.out.println("Constructor: " + constructor.getName());
Constructor: MyClass

Common Pitfalls and Considerations

  • Performance Overhead: Reflection is slower than direct access
  • Security Restrictions: Accessing private members might throw exceptions if security manager is active
  • Loss of Compile-time Safety: Errors show up only at runtime

Use Cases in Real-World Development

Reflection plays a crucial role in:

  • Frameworks like Spring and Hibernate
  • Dependency Injection
  • Testing Frameworks like JUnit
  • Object Mappers like Jackson or GSON

Important boundaries and mistakes

Reflection does not automatically bypass module or access restrictions. Failures often become runtime errors rather than compile-time checks.

Try the school example

Before running this Java program, write down each line you expect to see. Identify the value, branch, object or exception responsible for each line. Then explain whether the following assumption is valid: Reflection does not automatically bypass module or access restrictions.

Java 17 · Main.java · complete practice program

public class Main  {
  interface Named  {
    String label();
  }
  static class Student implements Named  {
    static String school = "River School";
    String name;
    Student(String name)  {
      this.name = name;
    }
    public String label()  {
      return name;
    }
  }
  public static void main(String[] args)  {
    Student s = new Student("Diya");
    System.out.println(s.getClass().getSimpleName());
  }
}

Worked answer and reasoning

Java 17 · Main.java · source repeated for this answer

public class Main  {
  interface Named  {
    String label();
  }
  static class Student implements Named  {
    static String school = "River School";
    String name;
    Student(String name)  {
      this.name = name;
    }
    public String label()  {
      return name;
    }
  }
  public static void main(String[] args)  {
    Student s = new Student("Diya");
    System.out.println(s.getClass().getSimpleName());
  }
}

Expected output

Student

Reflection inspects types and members while a program runs. It can discover a student’s class name, but direct calls remain clearer when the type is already known.

Reflection does not automatically bypass module or access restrictions. Failures often become runtime errors rather than compile-time checks.

Run with javac Main.java, then java Main. The declaration inside Main keeps the helper type available to this standalone example.

Check your understanding

For the complete practice program in this lesson, which output is expected on Java 17?
Choose one answer. You can try again.

Answer and explanation

Student

Reflection inspects types and members while a program runs. It can discover a student’s class name, but direct calls remain clearer when the type is already known. Reflection does not automatically bypass module or access restrictions. Failures often become runtime errors rather than compile-time checks.

What to remember

Reflection inspects types and members while a program runs. It can discover a student’s class name, but direct calls remain clearer when the type is already known. Reflection does not automatically bypass module or access restrictions. Failures often become runtime errors rather than compile-time checks.

Related explanations: Java Variables, Java If Statement - Syntax and Examples, Java Class - Blueprint of Objects, Exceptions in Java Introduction.

Supporting documentation: Official Java learning guide and Java 17 language specification.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Exceptions →