Basics of Reflection in Java


Reading time: 45 minutes | Coding time: 15 minutes

In Computer Programming, reflection is the process of examining and modifying the runtime behavior of applications.

In Java, Reflection is a powerful and advanced feature that enables the programmers to inspect or modify the classes, interfaces, and methods of a program running on Java Virtual Machine.

I hope you are experienced in writing Java classes, creating objects as well as invoking methods on an object. You must have used different classes and interfaces from java class libraries or from different third party APIs. As part of testing purpose or code analysis have you ever been asked to programmatically extract the meta-information of a class, like what are the modifiers used in the class definition, what are the constructors, fields, and methods defined inside that class, and so on? This can be achieved using the Java Reflection API.

For instance, you have been asked to write a program to print all the methods defined inside java.lang.String class. How will you do that?
Have a look at the below program.

import java.lang.reflect.*;

public class ReflectionTest {
    public static void main(String[] args) {
        Class classObject; // Reference of type Class
        try {
            classObject = Class.forName("java.lang.String"); // create an object of type Class which represent "java.lang.string" class
            Method[] methods = classObject.getDeclaredMethods();
            for (Method m : methods) {
                System.out.println(m.getName());
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

This program used two special reference types, Class and Method, that will be discussed shortly. classObject is a reference of type Class, which points to the class java.lang.String class and using that object invoked all the methods defined inside that class and printed to the console as shown below.

equals
toString
hashCode
compareTo
compareTo
indexOf
...

java.lang.Class

When a Java program runs, Java Runtime System keeps track of type information of all the object running on JVM that, the class to which each object belongs, using which the JVM can call appropriate methods on each object.
We can access runtime features of any object using a special class called Class. All Java types(Reference and Primitive types) can be represented as a Class object, in fact, class Class acts as the blueprint of Java types. Since the Class can contain meta-information of a class or interface it can also be called meta-class of a class.

  • Since the Class has no public constructors, all Class objects are constructed automatically by Java Virtual Machine.
  • We cannot create a Class instance using the new operator.
  • All Class objects are immutable.

In multiple ways you can retrieve Class objects inside your program, that explained in the following section.

  1. Using getClass() method

getClass() method can be called on any object, to get the information of the class to which this object belongs to. See the following examples.

String str = "hello world";
Class c = str.getClass();
Class c1 = "hello ".getClass();
class c2 = "world".getClass();

Here you can see three variables c, c1 and c2 are of type Class and they are all assigned the same Class object which represent the class String.

System.out.println(c);
System.out.println(c1);
System.out.println(c2);

This will print the following.

java.lang.String
java.lang.String
java.lang.String

If you call the getCalss() method on any of the String type objects, that will return a same java.lang.String Class object.

Let's see another example.

List<Integer> list = new ArrayList();
Class c = list.getClass();

Here the getclass() method returns the Class object representing the class java.util.ArrayList.

  1. Using Class.forName()

The class Class contains a static method forName(), using which you can access the Class object of any class, by passing the fully qualified name of the class.

Class c = Class.forName("java.lang.String");

Here the fully qualified name of the class String, java.lang.String has been passed to the method forName(), which then returns the Class object of the class java.lang.String.

  1. Using the .class syntax

By appending .class to the type name, you can access the Class object corresponding to that type. Lets see some examples.

Class c = int.class;

This will return a Class object corresponding to the primitive type int.

Class c = java.util.ArrayList.class;

This will return the Class object corresponding to the the class java.util.Arraylist.

Consider the reference type class. Now let’s see how we could access fields, methods, and constructors of a class using a Class object.

java.lang.reflect

java.lang.reflect package contains definitions of multiple classes which represent the properties of a class or interface. For example, the classes Field, Method, and Constructor represent the fields, methods, and constructors of a class respectively.
Most of the classes in this package haven't got a public constructor. In order to access the objects of these classes, appropriate methods on Class object needs to be invoked.

Consider the following Employee class, and let's see how to represent this class as an object of Class and try accessing the fields, constructors and methods defined inside it.

class Employee{
private long empId;
private String name;
private int age;

public Employee(){
}

public Employee(long empId, String name, int age){
    this.empId = empId;
    this.name = name;
    this.age = age;
}

public long getEmpId(){
    return empId;
}

public String getName(){
    return name;
}
    
public int getAge(){
    return age;
}    
}

Accessing the fields

class Class contains the following methods to access the fields defined in a class.

  • getField(String name) => Returns a Field object that corresponds to the specified public member field of the class represented by this Class object.
  • getFields() => Returns an array containing Field objects, which correspond to all the accessible public fields of the class represented by this Class object.
  • getDeclaredField(String name) => Returns a Field object that correposnds to the specified declared field of the class represented by this Class object.
  • getDeclaredFields() => Returns an array of Field objects correspond to all the fields declared by the class represented by this Class object.
Class c = Employee.class;
Field[] fields = c.getDeclaredFields();
for (Field f : fields) {
            System.out.println(f.getName());
        }

This will print the declared fields in the class Employee.

If you need to access the type of a field, the class Field has a method called, getType() which returns a Class object that identifies the declared type for the field represented by this Field object. See the below example.

Class c = Employee.class;
try {
      Field field = c.getDeclaredField("empId");// Accessing the field with name empId.
      System.out.println(field.getType());// accessing the type of specifield field
    } catch (Exception ex) {
            System.out.println("No such Field exists");
        }      

This code will print 'long' which is the type of the field empId. Field access statement enclosed in a try-catch block to avoid checked exception.

Accessing the methods
You can access the methods defined in a class or interface using the following methods defined in the corresponding Class object.

  • getDeclaredMethod(String name, Class<?>... parameterTypes) => Returns a Method object that corresponds to the specified declared method of the class or interface represented by this Class object.
  • getDeclaredMethods() => Returns an array containing Method objects corresponding to all the declared methods of the class or interface represented by this Class object, including public, protected, default and private methods, but excluding inherited methods.
  • getEnclosingMethod() => If the current Class object represents a local or anonymous class within a method, then this method returns a Method object representing the immediately enclosing method of the underlying class.
  • getMethod(String name, Class<?>... parameterTypes) => Returns a Method object that corresponds to the specified public member method of the class or interface represented by this Class object.
  • getMethods() => Returns an array containing Method objects correspond to all the public methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces.

The following code snippet illustrates, how to access the names of all the declared methods in the class Employee.

Employee e = new Employee();
Class c = e.getClass();
Method[] methods = c.getDeclaredMethods(); // Accessing all the declared methods in the class Employee
for (Method m : methods) {
   System.out.println(m.getName());
}

The java.lang.reflect.Method class acts as a meta-method which represents methods in a class. Using the methods defined in the class Method we can access the properties of a methods like, return type,parameter counts, parameter types etc.

Accessing the constructors

Like we accessed field and method details of a class, we can access the constructor details as well, using the the methods provided in the corresponding Class object.

  • getConstructor(Class<?>... parameterTypes) => Returns a Constructor object that corresponds to the specified public constructor of the class represented by this Class object.
  • getConstructors() => Returns an array containing Constructor objects correspond to all the public constructors of the class represented by this Class object.
  • getDeclaredConstructor(Class<?>... parameterTypes) => Returns a Constructor object that reflects the specified constructor of the class represented by this Class object.
  • getDeclaredConstructors() => Returns an array of Constructor objects corresponding to all the constructors declared by the class represented by this Class object.

See the sample code snippet below accessing the constructors of the class Employee.

Employee e = new Employee();
c = e.getClass();
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor cons : constructors) {
    System.out.println(cons.getName());
}

Like class Method, class Constructor also defines different methods to access the properties of a constructor, such as name, modifiers, parameters, parameter count etc.

For more details on the classes, Class, Field, Method, and Constructor read the below official documentation of java.lang.Class and java.lang.reflect .

Package summary of reflect

Java/lang/Class

Summary

  • Reflection permits a Java program to access the properties of a type
    (reference type as well as primitive types) during run time by creating a Class instance of the corresponding type.
  • java.lang.Class object is the starting point to use Reflection.
  • Class objects are created by JVM.
  • java.lang.reflect package contains definitions of special classes which represent the properties of a class.
  • class Class contains methods that can be invoked on a Class object to access the properties of a class, such as fields, methods, constructors, etc.