Java Reflection Explained: Access Private Fields, Methods & Internals with Examples

Master Java Reflection with real examples. Learn how to access private fields, invoke methods, and understand when and why reflection is used.

Java Reflection: Complete Guide

Reflection in Java is a powerful feature that allows a program to inspect and modify its own structure at runtime. You can access private fields, call methods dynamically, and even create objects without using constructors directly.

What is Reflection?

Reflection is part of java.lang.reflect package. It allows runtime access to class metadata such as fields, methods, constructors, and annotations.

Class<?> clazz = Class.forName("Bird");
  • Inspect class name, methods, fields
  • Access private members
  • Create objects dynamically
  • Invoke methods at runtime
  • Used in frameworks like Spring, Hibernate

Key Components of Reflection

  • Class → Entry point of reflection
  • Field → Represents class variables
  • Method → Represents methods
  • Constructor → Represents constructors

How to Get Class Object

Class<?> c1 = Bird.class;
Class<?> c2 = obj.getClass();
Class<?> c3 = Class.forName("Bird");

Accessing Fields

There are two important methods:

  • getField() → Only public fields
  • getDeclaredField() → All fields (private, protected, default)
Field f = clazz.getDeclaredField("breed");
f.setAccessible(true);
f.set(obj, "Eagle");

Accessing Methods

Method m = clazz.getDeclaredMethod("setBreed", String.class);
m.setAccessible(true);
m.invoke(obj, "Parrot");

Accessing Constructors

Constructor<?> cons = clazz.getConstructor();
Object obj = cons.newInstance();

Important Reflection Methods

  • getFields() → all public fields
  • getDeclaredFields() → all fields
  • getMethods() → all public methods
  • getDeclaredMethods() → all methods
  • getConstructors() → public constructors
  • newInstance() → create object
  • setAccessible(true) → bypass access control

Complex Example: Full Reflection Usage

import java.lang.reflect.*;

class Bird {
    private String breed;

    public Bird() {
        this.breed = "Unknown";
    }

    private void fly() {
        System.out.println("Bird is flying");
    }

    public String toString() {
        return "{breed=" + breed + "}";
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Bird.class;

        // Create object
        Object obj = clazz.getConstructor().newInstance();

        // Access private field
        Field field = clazz.getDeclaredField("breed");
        field.setAccessible(true);
        field.set(obj, "Eagle");

        // Call private method
        Method method = clazz.getDeclaredMethod("fly");
        method.setAccessible(true);
        method.invoke(obj);

        System.out.println(obj);
    }
}

Output

Bird is flying
{breed=Eagle}

Why Reflection is Used

  • Frameworks (Spring, Hibernate)
  • Dependency Injection
  • Serialization/Deserialization
  • Testing tools (JUnit)
  • Dynamic plugin systems

Disadvantages

  • Slow performance
  • Breaks encapsulation
  • Security restrictions
  • Hard to debug
  • Not type-safe

Best Practices

  • Avoid reflection unless necessary
  • Use it mainly in frameworks
  • Handle exceptions properly
  • Do not overuse setAccessible(true)
  • Prefer normal method calls when possible

Interview Tips

  • Reflection works at runtime
  • getField vs getDeclaredField is commonly asked
  • setAccessible(true) bypasses access control
  • Used heavily in Spring and Hibernate
  • Can modify private fields

Final Summary

  • Reflection allows runtime inspection and modification
  • Class is the entry point
  • Fields, Methods, Constructors are accessible
  • Powerful but risky
  • Use carefully in production systems