Question
What is reflection, and why is it useful?
I am particularly interested in Java, although I assume the general idea exists in other languages as well. Please explain what reflection means in Java, what kinds of things it allows a program to do, and why developers use it in practice.
Short Answer
By the end of this page, you will understand what reflection in Java is, how a program can inspect classes, methods, fields, and constructors at runtime, and why that can be useful in real applications. You will also learn the trade-offs: reflection is powerful, but it can make code slower, harder to read, and less safe if used carelessly.
Concept
Reflection is the ability of a program to inspect information about itself at runtime and, in many cases, interact with classes, methods, fields, and constructors dynamically.
In normal Java code, you usually know exactly what class and method you want to use:
User user = new User();
user.setName("Ava");
That is static and explicit. The compiler can check it.
With reflection, your code can do things like:
- load a class by name
- list its methods and fields
- create an object without directly calling
new - call a method by its name stored in a string
- read or write a field dynamically
- inspect annotations and metadata
For example, a framework may receive the class name "com.example.UserService" from configuration, load that class at runtime, create an instance, and call methods on it.
In Java, reflection is mainly provided through classes in the java.lang.reflect package and through the Class type.
Why reflection matters
Reflection matters because real software often needs to work with code that is not fully known at compile time.
Examples:
- frameworks that automatically create objects
- dependency injection containers like Spring
- test tools that discover test methods
- serializers that convert objects to JSON or XML
- ORMs that map Java classes to database tables
- plugin systems that load classes dynamically
Without reflection, many of these tools would require much more manual wiring.
Important trade-offs
Reflection is useful, but it comes with costs:
- Less type safety: method names and field names may be strings, so mistakes are found later
- Harder to read: reflective code is more indirect than normal method calls
- Performance overhead: reflective access is usually slower than direct access
- Encapsulation issues: reflection can access internals that normal code should not touch
So reflection is best used when you need flexibility at runtime, especially in libraries, frameworks, and infrastructure code.
Mental Model
Think of a Java class as a machine inside a sealed box.
Normally, you use the machine through its visible buttons and controls:
- create it with
new - call methods directly
- read public fields
Reflection is like having a technical inspection manual and a toolkit that lets you:
- read the label on the box
- see what parts are inside
- discover which buttons exist
- press a button by name
- inspect private compartments if access rules allow it
So instead of saying, "Call save() on this exact type," reflection lets you say, "If this object has a method called save, find it and run it."
That flexibility is powerful, especially for frameworks, but it is also easier to misuse than normal direct code.
Syntax and Examples
Core reflection building blocks in Java
The main pieces are:
Class<?>— represents a class at runtimeField— represents a fieldMethod— represents a methodConstructor<?>— represents a constructor
Example class
class Person {
private String name;
public Person() {
this.name = "Unknown";
}
public void sayHello() {
System.out.println("Hello, " + name);
}
}
Get class information
Class<?> clazz = Person.class;
System.out.println(clazz.getName());
System.out.println(clazz.getSimpleName());
This prints the full class name and the short class name.
Create an object reflectively
Class<?> clazz = Person.class;
Object obj = clazz.getDeclaredConstructor().newInstance();
Step by Step Execution
Consider this example:
import java.lang.reflect.Method;
class Calculator {
public int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<?> clazz = Calculator.class;
Object calculator = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getMethod("add", int.class, int.class);
Object result = method.invoke(calculator, 3, 4);
System.out.println(result);
}
}
What happens step by step
-
Class<?> clazz = Calculator.class;- Java gets the runtime representation of the
Calculatorclass.
- Java gets the runtime representation of the
Real World Use Cases
Where reflection is used in practice
Dependency injection frameworks
Frameworks like Spring inspect classes, constructors, fields, and annotations to create objects automatically and connect dependencies.
Example idea:
- find a class marked with
@Service - create an instance
- inject required dependencies
Testing frameworks
JUnit can discover methods marked as tests and execute them without you calling each test manually.
Serialization and deserialization
Libraries inspect object fields and convert them to JSON, XML, or other formats.
Example:
- read all fields of a
Userobject - turn them into JSON properties
ORM tools
Frameworks such as Hibernate inspect entity classes and map fields to database columns.
Plugin systems
Applications can load classes by name from configuration files or external modules.
Example:
- config says to use
StripePaymentProcessor - app loads that class at runtime
Annotation processing at runtime
Many frameworks inspect annotations such as routing, validation, or configuration annotations.
Example:
@GetMapping("/users")
Real Codebase Usage
In real projects, reflection is usually not spread across all business logic. Instead, developers tend to keep it in infrastructure layers such as frameworks, utility libraries, mappers, and bootstrapping code.
Common patterns
1. Object creation from configuration
A config file may contain a class name:
String className = "com.example.EmailService";
Class<?> clazz = Class.forName(className);
Object service = clazz.getDeclaredConstructor().newInstance();
This is common in plugin systems and older factory-style designs.
2. Annotation scanning
Developers inspect classes and methods for annotations:
if (clazz.isAnnotationPresent(MyService.class)) {
// register the class as a service
}
This pattern is heavily used in frameworks.
3. Validation utilities
A validation library may inspect fields and apply rules dynamically.
Example idea:
- field has
@NotNull - framework checks whether the field value is null
4. Guard clauses around reflection
Because reflection can fail at runtime, code often checks carefully and fails early.
Common Mistakes
1. Using reflection when normal code is better
Beginners sometimes use reflection just because it seems powerful.
Overcomplicated
Method m = user.getClass().getMethod("getName");
String name = (String) m.invoke(user);
Better
String name = user.getName();
If you already know the type and method, direct code is simpler and safer.
2. Forgetting exception handling
Reflection often throws checked exceptions.
Broken assumption:
Class<?> clazz = Class.forName("com.example.MissingClass");
If the class does not exist, this fails at runtime.
Avoid this by handling exceptions carefully and giving clear error messages.
3. Misspelling method or field names
Reflection often uses strings, so the compiler cannot help as much.
clazz.getMethod("syaHello"); // typo
This causes NoSuchMethodException.
Comparisons
Reflection vs normal Java calls
| Aspect | Normal code | Reflection |
|---|---|---|
| Method known at compile time | Yes | Not required |
| Type safety | Stronger | Weaker |
| Readability | Easier | Harder |
| Performance | Faster | Usually slower |
| Flexibility | Lower | Higher |
| Typical use | Application logic | Frameworks, tooling, dynamic systems |
Class.forName() vs .class
| Syntax | Use case |
|---|
Cheat Sheet
Reflection quick reference
Get a Class object
Person.class
obj.getClass()
Class.forName("com.example.Person")
Create an object
Object obj = clazz.getDeclaredConstructor().newInstance();
Get a public method
Method m = clazz.getMethod("methodName", String.class, int.class);
Get any method declared in the class
Method m = clazz.getDeclaredMethod("methodName");
Call a method
Object result = m.invoke(obj, arg1, arg2);
Get a field
clazz.getDeclaredField();
FAQ
What is reflection in Java in simple terms?
Reflection lets a Java program inspect and use classes, methods, fields, and constructors at runtime, even when they are not hardcoded directly.
Why is reflection useful in Java?
It is useful when code needs runtime flexibility, such as loading classes from configuration, scanning annotations, creating objects dynamically, or building frameworks.
Is reflection slow in Java?
It is usually slower than direct method calls, but often acceptable for startup logic, framework code, and tools. It should be used carefully in performance-critical paths.
Is reflection bad practice?
Not by itself. It is a tool. It becomes a problem when used where normal Java code would be clearer, safer, and simpler.
Can reflection access private fields and methods?
Yes, in many cases it can access private members using reflective APIs, but this should be done carefully because it weakens encapsulation.
Do Java frameworks use reflection?
Yes. Many popular frameworks use reflection for dependency injection, serialization, testing, ORM mapping, and annotation scanning.
Is reflection the same in every programming language?
The idea is similar across languages: inspect and use program structure at runtime. However, each language provides different APIs, limitations, and conventions.
Mini Project
Description
Build a small Java utility that loads a class, creates an object, and runs a method by name. This demonstrates the main practical value of reflection: working with code that is only known at runtime rather than hardcoded at compile time.
Goal
Create a program that dynamically instantiates a class and invokes a method using reflection.
Requirements
- Create a class with at least one public no-argument method.
- Use reflection to get the class object.
- Create an instance without calling
newdirectly. - Invoke a method by its name.
- Print the result or visible output to confirm it worked.
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.