--- title: Reflection in Java - Scaler Topics description: This article by Scaler Topics covers What is Reflection in Java with applications, examples, and explanations; read to know more. category: Java author: Priyansh Goyal --- :::section{.main} Reflection in Java is a unique feature in the Java programming language that provides us with a way to get information regarding the class to which an object belongs and the methods of that class that can be executed using that object. We can use Java Reflection to invoke these methods at runtime without knowing their names and change their behaviour at runtime. [IMAGE {1} {CREATE A SIMILAR GRAPHIC} START SAMPLE] https://media.geeksforgeeks.org/wp-content/uploads/20220110121120/javalang.jpg [IMAGE {1} FINISH SAMPLE] ### Uses of Reflection Reflection in Java is a powerful feature with various use cases: * It allows classes to be loaded dynamically at runtime, enabling applications to load classes that are not known at compile time. * It is commonly used in debugging and testing frameworks to inspect and manipulate objects during runtime, facilitating the creation of generic test cases and debugging tools. * Frameworks like Spring use reflection extensively for configuration and dependency injection, allowing developers to define beans and wire dependencies without explicit configuration. * It plays a crucial role in serialization and deserialization mechanisms, where objects are converted to and from byte streams. Libraries like Jackson and Gson utilize reflection to map Java objects to JSON and vice versa. While reflection provides flexibility and power, it should be used judiciously due to its performance overhead and potential security risks. ### How to Invoke a Method through Reflection? #### Method 1: getDeclaredMethod() `getDeclaredMethod()` is a method the Java Reflection API provides. It allows you to obtain a Method object representing a method of a class, including non-public methods. #### Method 2: invoke() The `invoke()` method, part of Java's Reflection API, executes a method dynamically. It's called on a Method object obtained through reflection, taking the target object instance (or null for static methods) and method arguments as parameters. ```java package org.scaler.note; public class Employee { private String name; private double salary; public Employee(String name, double salary) { this.name = name; this.salary = salary; } public double calculateSalary(double bonus) { return this.salary + bonus; } } ``` ```java import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) throws Exception { // Get the class object for Employee Class<?> employeeClass = Class.forName("org.scaler.note.Employee"); // Get the method object for calculateSalary with parameter type double Method calculateSalaryMethod = employeeClass.getDeclaredMethod("calculateSalary", double.class); // Create an instance of Employee Object employeeInstance = employeeClass.getConstructor(String.class, double.class).newInstance("John", 50000.0); // Invoke the calculateSalary method with a bonus of 2000 double bonus = 2000; double totalSalary = (double) calculateSalaryMethod.invoke(employeeInstance, bonus); System.out.println("Total Salary: " + totalSalary); } } ``` **Output:** ```plaintext Total Salary: 52000.0 ``` **Explanation:** In this example, after creating an instance of Employee, we directly obtain the Method object for calculateSalary using getDeclaredMethod(). Then, we set its accessibility to true (if it's private) and invoke it using the invoke() method, passing the instance of Employee and the bonus parameter. Finally, we print the total salary returned using this method. #### Method 3: Class.getDeclaredField(FieldName) The `getDeclaredField()` method retrieves a Field object representing a declared field of the class. It allows access to non-public fields and accepts the field name as its parameter. This facilitates dynamic access to class fields during runtime via reflection in Java. #### Method 4: Field.setAccessible(true) The setAccessible(accurate) method, employed on a Field object obtained through reflection, enables access to non-public fields. It overrides access restrictions, allowing modification or retrieval of field values that would otherwise be inaccessible due to encapsulation. ```java package org.scaler.note; public class Employee { private double salary; public Employee(double salary) { this.salary = salary; } // Getter and setter for salary (not shown for brevity) } ``` ```java import java.lang.reflect.Field; public class ReflectionExample { public static void main(String[] args) throws Exception { // Get the class object for Employee Class<?> employeeClass = Class.forName("org.scaler.note.Employee"); // Create an instance of Employee Object employeeInstance = employeeClass.getConstructor(double.class).newInstance(50000.0); // Get the field object for the private field 'salary' Field salaryField = employeeClass.getDeclaredField("salary"); // Make the field accessible (since it's private) salaryField.setAccessible(true); // Get the current value of the salary field double currentSalary = (double) salaryField.get(employeeInstance); System.out.println("Current Salary: " + currentSalary); // Modify the value of the salary field salaryField.set(employeeInstance, 55000.0); // Get the updated value of the salary field double updatedSalary = (double) salaryField.get(employeeInstance); System.out.println("Updated Salary: " + updatedSalary); } } ``` **Output:** ```plaintext Current Salary: 50000.0 Updated Salary: 55000.0 ``` **Explanation:** In this example, we first obtain the Class object for Employee. Then, we create an instance of Employee using reflection. Next, we use getDeclaredField() to obtain a reference to the private salary field. After making the field accessible, we can get its current value using get() and modify it using set(). Finally, we print the salary field's current and updated values. ::: :::section{.main} ## Important Points on Reflection API in Java 1. The Reflection API in Java allows for dynamic inspection and manipulation of classes, interfaces, fields, and methods at runtime. 2. It provides a way to dynamically analyze and modify the structure and behaviour of Java applications. 3. Reflection can be used for tasks such as introspecting classes, accessing private members, invoking methods dynamically, and creating instances of classes dynamically. 4. While powerful, reflection should be used judiciously due to its potential performance overhead and complexity. 5. It enables frameworks like Spring and Hibernate to perform tasks like dependency injection and object-relational mapping without requiring explicit configuration. 6. Reflection can be beneficial in scenarios where the structure of classes is not known at compile time, such as in generic programming or plugin systems. 7. Java's Reflection API is integral to many advanced Java libraries and frameworks, facilitating tasks such as serialization, testing, and debugging. 8. Security concerns arise with reflection, as it can be used to access sensitive information or modify critical components of a Java application. 9. Despite its power, developers should strive to minimize the use of reflection in performance-critical code and favour more straightforward, statically-typed alternatives where possible. 10. Proper understanding and usage of the Reflection API can significantly enhance the flexibility and capabilities of Java applications, but it should be employed thoughtfully and with caution. ### Example ```java import java.lang.annotation.*; import java.lang.reflect.*; class Person { private int id; private String name; private int age; public Person(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } public static void main(String[] args) { Class<?> c = Person.class; // Constructor array Constructor<?>[] constructors = c.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("Name of Constructor : " + constructor); System.out.println("Count of constructor parameters : " + constructor.getParameterCount()); Parameter[] parameters = constructor.getParameters(); for (Parameter parameter : parameters) { System.out.println("Constructor's parameter : " + parameter); } System.out.println(); } System.out.println(); // Method Array Method[] methods = c.getDeclaredMethods(); System.out.println("Length of methods : " + methods.length); for (Method method : methods) { System.out.println("Method name: \t" + method); System.out.println("Method return type : \t" + method.getReturnType()); System.out.println("Method parameter count: \t" + method.getParameterCount()); Parameter[] parameters = method.getParameters(); for (Parameter parameter : parameters) { System.out.println("Method's Parameter : " + parameter); } System.out.println(); } System.out.println(); // Annotations Class<?>[] classes = c.getDeclaredClasses(); for (Class<?> class1 : classes) { System.out.println("class: " + class1); System.out.println("Name of class: " + class1.getName()); } System.out.println(); // Annotations Annotation[] anno = c.getDeclaredAnnotations(); for (Annotation annotation : anno) { System.out.println("Annotation: " + annotation); } } } ``` **Output:** ```plaintext Name of Constructor : public Person(int,java.lang.String,int) Count of constructor parameters : 3 Constructor's parameter : int arg0 Constructor's parameter : java.lang.String arg1 Constructor's parameter : int arg2 Length of methods : 8 Method name: public void Person.setId(int) Method return type : void Method parameter count: 1 Method's Parameter : int arg0 Method name: public int Person.getAge() Method return type : int Method parameter count: 0 Method name: public void Person.setAge(int) Method return type : void Method parameter count: 1 Method's Parameter : int arg0 Method name: public static void Person.main(java.lang.String[]) Method return type : void Method parameter count: 1 Method's Parameter : java.lang.String[] arg0 Method name: public java.lang.String Person.toString() Method return type : class java.lang.String Method parameter count: 0 Method name: public java.lang.String Person.getName() Method return type : class java.lang.String Method parameter count: 0 Method name: public void Person.setName(java.lang.String) Method return type : void Method parameter count: 1 Method's Parameter : java.lang.String arg0 Method name: public int Person.getId() Method return type : int Method parameter count: 0 ``` ::: ::: section{.main} ## Advantages and Disadvantages of Reflection in Java **Advantages:** 1. It enables dynamic runtime inspection of classes, interfaces, methods, and fields. 2. It allows the invocation of methods, instantiation of classes, and modification of field values dynamically. 3. It facilitates the development of Visual Development Environments and class browsers, aiding developers in writing correct code. **Disadvantages:** 1. It violates encapsulation principles by allowing access to private methods and fields, potentially leaking sensitive data. 2. It introduces performance overhead as types are resolved dynamically, preventing JVM optimization and resulting in slower operations. ::: :::section{.summary} ## Conclusion * **Reflection in Java** is a way through which we can gather information about classes and their methods and alter or modify their behaviour at runtime. * It provides dynamic access to class metadata, enabling tasks like instantiation, method invocation, and field manipulation. * It supports frameworks and libraries that require runtime analysis and manipulation of classes and objects. * It increased flexibility in implementing advanced debugging, logging, and testing functionalities. * However, Reflection should be used judiciously due to potential performance overhead, security concerns, and increased code complexity. :::