What is the Reflection API for?
Java's reflection mechanism allows a developer to make changes and obtain information about classes, interfaces, fields, and methods at runtime without knowing their names.
The Reflection API also lets you create new objects, call methods, and get or set field values.
Let's make a list of everything you can do using reflection:
- Identify/determine the class of an object
- Get information about class modifiers, fields, methods, constants, constructors, and superclasses
- Find out which methods belong to implemented interface(s)
- Create an instance of a class whose class name is not known until the program is executed
- Get and set the value of an instance field by name
- Call an instance method by name
Almost all modern Java technologies use reflection. It underlies most of today's Java / Java EE frameworks and libraries, for example:
- Spring frameworks for building web applications
- the JUnit testing framework
If you've never encountered these mechanisms before, you're probably asking why is all this necessary. The answer is quite simple but also very vague: reflection dramatically increases flexibility and the ability to customize our application and code.
But there are always pros and cons. So let's mention a few cons:
- Violations of application security. Reflection lets us access code that we shouldn't (violation of encapsulation).
- Security restrictions. Reflection requires runtime permissions that are not available to systems running a security manager.
- Low performance. Reflection in Java determines types dynamically by scanning the classpath to find the class to load. This reduces the program's performance.
- Difficult to maintain. Code that uses reflection is difficult to read and debug. It is less flexible and harder to maintain.
Working with classes using the Reflection API
All reflection operations begin with a java.lang.Class object. For each type of object, an immutable instance of java.lang.Class is created. It provides methods for getting object properties, creating new objects, and calling methods.
Let's look at the list of basic methods for working with java.lang.Class:
Method | Action |
---|---|
String getName(); | Returns the name of the class |
int getModifiers(); | Returns access modifiers |
Package getPackage(); | Returns information about a package |
Class getSuperclass(); | Returns information about a parent class |
Class[] getInterfaces(); | Returns an array of interfaces |
Constructor[] getConstructors(); | Returns information about class constructors |
Fields[] getFields(); | Returns the fields of a class |
Field getField(String fieldName); | Returns a specific field of a class by name |
Method[] getMethods(); | Returns an array of methods |
These are the most important methods for getting data about classes, interfaces, fields, and methods. There are also methods that let you get or set field values, and access private fields. We'll look at them a little later.
Right now we'll talk about getting the java.lang.Class itself. We have three ways to do this.
1. Using Class.forName
In a running application, you must use the forName(String className) method to get a class.
This code demonstrates how we can create classes using reflection. Let's create a Person class that we can work with:
package com.company;
public class Person {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And the second part of our example is the code that uses reflection:
public class TestReflection {
public static void main(String[] args) {
try {
Class<?> aClass = Class.forName("com.company.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
This approach is possible if the full name of the class is known. Then you can get the corresponding class using the static Class.forName() method. This method cannot be used for primitive types.
2. Using .class
If a type is available but there is no instance of it, then you can get the class by adding .class to the type name. This is the easiest way to get the class of a primitive type.
Class aClass = Person.class;
3. Using .getClass()
If an object is available, then the easiest way to get a class is to call object.getClass().
Person person = new Person();
Class aClass = person.getClass();
What's the difference between the last two approaches?
Use A.class if you know which class object you are interested in at coding time. If no instance is available, then you should use .class.
Getting the methods of a class
Let's look at the methods that return the methods of our class: getDeclaredMethods() and getMethods().
getDeclaredMethods() returns an array that contains Method objects for all declared methods of the class or interface represented by the Class object, including public, private, default, and protected methods, but not inherited methods.
getMethods() returns an array containing Method objects for all public methods of the class or interface represented by the Class object — those declared by the class or interface, as well as those inherited from superclasses and superinterfaces.
Let's take a look at how each of them works.
Let's start with getDeclaredMethods(). To again help us understand the difference between the two methods, below we will work with the abstract Numbers class. Let's write a static method that will convert our Method array to List<String>:
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TestReflection {
public static void main(String[] args) {
final Method[] declaredMethods = Number.class.getDeclaredMethods();
List<String> actualMethodNames = getMethodNames(declaredMethods);
actualMethodNames.forEach(System.out::println);
}
private static List<String> getMethodNames(Method[] methods) {
return Arrays.stream(methods)
.map(Method::getName)
.collect(Collectors.toList());
}
}
Here's the result of running this code:
shortValue
intValue
longValue
float floatValue;
doubleValue
These are the methods declared inside the Number class. What does getMethods() return? Let's change two lines in the example:
final Method[] methods = Number.class.getMethods();
List<String> actualMethodNames = getMethodNames(methods);
Doing this, we will see the following set of methods:
shortValue
intValue
longValue
float floatValue;
doubleValue
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
Because all classes inherit Object, our method also returns the public methods of the Object class.
Getting the fields of a class
The getFields and getDeclaredFields methods are used to get the fields of a class. As an example, let's look at the LocalDateTime class. We'll rewrite our code:
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TestReflection {
public static void main(String[] args) {
final Field[] declaredFields = LocalDateTime.class.getDeclaredFields();
List<String> actualFieldNames = getFieldNames(declaredFields);
actualFieldNames.forEach(System.out::println);
}
private static List<String> getFieldNames(Field[] fields) {
return Arrays.stream(fields)
.map(Field::getName)
.collect(Collectors.toList());
}
}
As a result of executing this code, we get the set of fields contained in the LocalDateTime class.
MAX
serialVersionUID
date
time
By analogy with our previous examination of methods, let's see what happens if we change the code a little:
final Field[] fields = LocalDateTime.class.getFields();
List<String> actualFieldNames = getFieldNames(fields);
Output:
MAX
Now let's figure out the difference between these methods.
The getDeclaredFields method returns an array of Field objects for all fields declared by the class or interface represented by this Class object.
The getFields method returns an array of Field objects for all public fields of the class or interface represented by the Class object.
Now let's look inside LocalDateTime.

The class's MIN and MAX fields are public, which means they will be visible through the getFields method. By contrast, the date, time, serialVersionUID methods have the private modifier, which means they will not be visible through the getFields method, but we can get them using getDeclaredFields. This is how we can access Field objects for private fields.
Descriptions of other methods
Now its time to talk about some methods of the Class class, namely:
Method | Action |
---|---|
getModifiers | Getting the modifiers for our class |
getPackage | Getting the package that contains our class |
getSuperclass | Getting the parent class |
getInterfaces | Getting an array of interfaces implemented by a class |
getName | Getting the fully qualified class name |
getSimpleName | Getting the name of a class |
getModifiers()
Modifiers can be accessed using a Class object.
Modifiers are keywords like public, static, interface, etc. We get modifiers using the getModifiers() method:
Class<Person> personClass = Person.class;
int classModifiers = personClass.getModifiers();
This code sets the value of an int variable that is a bit field. Each access modifier can be turned on or off by setting or clearing the corresponding bit. We can check modifiers using the methods in the java.lang.reflect.Modifier class:
import com.company.Person;
import java.lang.reflect.Modifier;
public class TestReflection {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
int classModifiers = personClass.getModifiers();
boolean isPublic = Modifier.isPublic(classModifiers);
boolean isStatic = Modifier.isStatic(classModifiers);
boolean isFinal = Modifier.isFinal(classModifiers);
boolean isAbstract = Modifier.isAbstract(classModifiers);
boolean isInterface = Modifier.isInterface(classModifiers);
System.out.printf("Class modifiers: %d%n", classModifiers);
System.out.printf("Is public: %b%n", isPublic);
System.out.printf("Is static: %b%n", isStatic);
System.out.printf("Is final: %b%n", isFinal);
System.out.printf("Is abstract: %b%n", isAbstract);
System.out.printf("Is interface: %b%n", isInterface);
}
}
Recall what the declaration of our Person looks like:
public class Person {
…
}
We get the following output:
Is public: true
Is static: false
Is final: false
Is abstract: false
Is interface: false
If we make our class abstract, then we have:
public abstract class Person { … }
and this output:
Is public: true
Is static: false
Is final: false
Is abstract: true
Is interface: false
We changed the access modifier, which means we also changed the data returned through the static methods of the Modifier class.
getPackage()
Knowing only a class, we can get information about its package:
Class<Person> personClass = Person.class;
final Package aPackage = personClass.getPackage();
System.out.println(aPackage.getName());
getSuperclass()
If we have a Class object, then we can access its parent class:
public static void main(String[] args) {
Class<Person> personClass = Person.class;
final Class<? super Person> superclass = personClass.getSuperclass();
System.out.println(superclass);
}
We get the well-known Object class:
class java.lang.Object
But if our class has another parent class, then we will see it instead:
package com.company;
class Human {
// Some info
}
public class Person extends Human {
private int age;
private String name;
// Some info
}
Here we get our parent class:
class com.company.Human
getInterfaces()
Here's how we can get the list of interfaces implemented by the class:
public static void main(String[] args) {
Class<Person> personClass = Person.class;
final Class<?>[] interfaces = personClass.getInterfaces();
System.out.println(Arrays.toString(interfaces));
}
And let's not forget to change our Person class:
public class Person implements Serializable { … }
Output:
A class can implement many interfaces. That's why we get an array of Class objects. In the Java Reflection API, interfaces are also represented by Class objects.
Please note: The method returns only the interfaces implemented by the specified class, not its parent class. To get a complete list of interfaces implemented by the class, you need to refer to both the current class and all its ancestors up the inheritance chain.
getName() & getSimpleName() & getCanonicalName()
Let's write an example involving a primitive, a nested class, an anonymous class, and the String class:
public class TestReflection {
public static void main(String[] args) {
printNamesForClass(int.class, "int class (primitive)");
printNamesForClass(String.class, "String.class (ordinary class)");
printNamesForClass(java.util.HashMap.SimpleEntry.class,
"java.util.HashMap.SimpleEntry.class (nested class)");
printNamesForClass(new java.io.Serializable() {
}.getClass(),
"new java.io.Serializable(){}.getClass() (anonymous inner class)");
}
private static void printNamesForClass(final Class<?> clazz, final String label) {
System.out.printf("%s:%n", label);
System.out.printf("\tgetName()):\t%s%n", clazz.getName());
System.out.printf("\tgetCanonicalName()):\t%s%n", clazz.getCanonicalName());
System.out.printf("\tgetSimpleName()):\t%s%n", clazz.getSimpleName());
System.out.printf("\tgetTypeName():\t%s%n%n", clazz.getTypeName());
}
}
Result of our program:
getName()): int
getCanonicalName()): int
getSimpleName()): int
getTypeName(): int
String.class (ordinary class):
getName()): java.lang.String
getCanonicalName()): java.lang.String
getSimpleName()): String
getTypeName(): java.lang.String
java.util.HashMap.SimpleEntry.class (nested class):
getName()): java.util.AbstractMap$SimpleEntry
getCanonicalName()): java.util.AbstractMap.SimpleEntry
getSimpleName()): SimpleEntry
getTypeName(): java.util.AbstractMap$SimpleEntry
new java.io.Serializable(){}.getClass() (anonymous inner class):
getName()): TestReflection$1
getCanonicalName()): null
getSimpleName()):
getTypeName(): TestReflection$1
Now let's analyze our program's output:
getName() returns the name of the entity.
getCanonicalName() returns the canonical name of the base class, as defined by the Java Language Specification. Returns null if the base class does not have a canonical name (that is, if it is a local or anonymous class or an array whose element type does not have a canonical name).
getSimpleName() returns the simple name of the base class as specified in the source code. Returns an empty string if the base class is anonymous.
getTypeName() returns an informative string for the name of this type.
GO TO FULL VERSION