Reflection is an API that is used to examine or modify the behaviour of methods, classes, and interfaces at runtime.
Java reflection, which allows us to
- Inspect classes, methods, fields, and constructors at runtime.
- Access and modify private fields/methods.
- Instantiate objects dynamically.
- Invoke methods or create proxies dynamically.
Reflection is part of the java.lang.reflect
package and shipped with the JDK, it is used extensively by different Java frameworks and libraries.
Drawbacks
- Performance overhead
- Slower than direct method calls or field access.
- Security risks
- Can bypass private access modifiers, leading to potential vulnerabilities.
- Compile-time safety
- Errors only show at runtime, not during compilation.
Getting the class object
The entry point for reflection is the Class
object (java.lang.Class
). Each class or interface loaded into the JVM is represented by an object of the Class
class. A Class
object contains metadata about a class, such as:
- The class name.
- Its fields, methods, and constructors.
- Annotations, superclasses, and implemented interfaces.
There are three ways of getting the class object.
.class
- The
.class
literal is a compile-time way of getting theClass
object for a specific class or interface. It is used when the class is known at compile time and does not require an instance of the class
- The
getClass()
- The
getClass()
method is used to obtain theClass
object of the runtime class of an object instance. It is used when you have an instance of the class, and you want to dynamically obtain itsClass
object, it requires an instance of the class to call the method.
- The
Class.forName()
- The
Class.forName()
method is used to load a class dynamically by its fully qualified name (package + class name) as a string. It is used when the class name is not known at compile time and must be determined at runtime (e.g., from a configuration file or user input). It requires the fully qualified name of the class as a string.
- The
Class<?> cls1 = String.class; // Using the .class syntax
Class<?> cls2 = "Hello".getClass(); // Using the object's getClass() method
Class<?> cls3 = Class.forName("java.lang.String"); // Using Class.forName()
System.out.println(cls1.getName());
System.out.println(cls2.getName());
System.out.println(cls3.getName());
java.lang.String
java.lang.String
java.lang.String
Inspect class information
You can inspect modifiers, fields, methods, constructors, and superclass of a class.
Class<?> cls = Class.forName("java.util.ArrayList");
// Class name
System.out.println("Class Name: " + cls.getName());
// Modifiers
int modifiers = cls.getModifiers();
System.out.println("Is Public? " + Modifier.isPublic(modifiers));
// Superclass
System.out.println("Superclass: " + cls.getSuperclass());
// Implemented interfaces
Class<?>[] interfaces = cls.getInterfaces();
System.out.println("Interfaces:");
for (Class<?> i : interfaces) {
System.out.println(" - " + i.getName());
}
Class Name: java.util.ArrayList
Is Public? true
Superclass: class java.util.AbstractList
Interfaces:
- java.util.List
- java.util.RandomAccess
- java.lang.Cloneable
- java.io.Serializable
Accessing fields
Fields (including private ones) can be accessed and modified using reflection.
class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person person = new Person("John");
// Access the private field
Field field = Person.class.getDeclaredField("name");
field.setAccessible(true); // Bypass private access
// Get and modify the value
System.out.println("Original name: " + field.get(person));
field.set(person, "Alice");
System.out.println("Modified name: " + field.get(person));
}
}
Original name: John
Modified name: Alice
Access to multiple fields
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
People p1 = new People(20, "John");
Field[] fields = p1.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("age")) {
System.out.println("Age: " + field.get(p1));
}
if (field.getName().equals("name")) {
System.out.println("Name: " + field.get(p1));
}
}
}
}
Age: 20
Name: John
Accessing Methods
Methods can be invoked dynamically.
class Calculator {
public int add(int a, int b) { return a + b; }
}
public class Demo {
public static void main(String[] args) {
Calculator calc = new Calculator();
// Get the method
Method method = Calculator.class.getMethod("add", int.class, int.class);
// Invoke the method
int result = (int) method.invoke(math, 5, 3);
System.out.println("Result: " + result);
}
}
8
Accessing constructors
class Student {
private String name;
private age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ConstructorReflectionExample {
public static void main(String[] args) throws Exception {
// Get the constructor
Constructor<Student> constructor = Student.class.getConstructor(String.class, int.class);
// Create a new instance
Student student = constructor.newInstance("Emma", 19);
}
}
Back to parent page: Java
Web_and_App_Development Programming_Languages Java Reflection
Referece: