- Published on
Java Reflection
- Authors
- Name
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.