Cristian Riță
Published on

Java Reflection

Authors
  • Name
    Twitter

Introduction

The Java Reflection API is a powerful tool that allows us to inspect and modify the behavior of classes, interfaces, fields and methods at runtime. When we have to work with classes that we don't know at compile time, the Reflection API is the way to go.

Reflection is an advanced feature of the Java language and is mainly used in frameworks and libraries. java.lang.reflect is the package that contains all the classes and interfaces needed to use the Reflection API.

Class class

When we run an application, the JVM loads the classes that are needed to run the application. The Class represents a class or an interface loaded by the JVM. Although the Class is not part of the 'java.lang.reflect' package, it is a fundamental part of the Reflection mechanism.

class Student {
    private Long id;
    public String name;
    public String email;

    public Student(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
        return this.name;
    }

    private void generateId() {
        this.id = System.currentTimeMillis();
    }

    public String getEmail() {
        return this.email;
    }
}

public class ReflectionExample {
    public static void main(String[] args) {
        Student student = new Student("John", "john@doe.com");
        Class<?> studentClass = student.getClass();
        System.out.println(studentClass.getName());

        System.out.println("Fields:");
        Arrays.stream(studentClass.getFields()).forEach(System.out::println);
        System.out.println("Methods:");
        Arrays.stream(studentClass.getMethods()).forEach(System.out::println);
    }
}

Class is a generic type, so we can use the wildcard <? extends Student> to specify that we want to get the class of a Student or any subclass of Student. Once we have the class, we can get the name of the class with getName(), the fields with getFields() and the methods with getMethods().

One thing to note is that getFields() returns only the public fields of the class. The same applies to getMethods().

If we want to get all the fields and methods of the class, we can use getDeclaredFields() and getDeclaredMethods(). Although it is possible to access private fields and methods, it is not recommended to do so. Encapsulation is a fundamental principle of object-oriented programming and we should not break it.

Field, Method and Constructor classes

As we saw in the previous section, the Class class allows us to get the fields and methods of a class. getFields() and getMethods() return an array of Field and Method respectively. Intuitively, Field represents a field of a class and Method represents a method of a class. Both classes are part of the java.lang.reflect package. Another class that is part of the java.lang.reflect package is Constructor. As the name suggests, Constructor represents a constructor of a class.

Constructor<?>[] constructors = Class.forName("java.lang.String").getConstructors();
Arrays.stream(constructors).forEach(System.out::println);

The code above prints the constructors of the String class. The Class.forName() method returns the class with the specified name.

Having a constructor, we can create an instance of a class with the newInstance() method.

    String hello = "Hello";
    Constructor<?> constructor = hello.getClass().getConstructor(hello.getClass());
    String world = (String) constructor.newInstance("World");
    System.out.println(world);

The code above prints World. The newInstance() method returns an Object, so we have to cast it to the type we want. Similary we can invoke a method of a class with the invoke() method.

    String hello = "Hello";
    Method method = hello.getClass().getMethod("concat", String.class);
    String world = (String) method.invoke(hello, "World");
    System.out.println(world);

Conclusion

Modifyin the behavior of classes at runtime is a powerful feature of the Java language. However, it is an advanced feature and should be used with caution.

Did you enjoy this article? You might also like my Spring Framework newsletters: