Key Takeaways
- Java’s Reflection API allows developers to inspect and manipulate types, methods, fields, annotations, etc. at run time, enabling interaction with types that weren’t known at compile time. This can be particularly useful in frameworks and extensible applications that need to load user-provided plugins at run time.
- The gateway into the reflection API is Class::forName, which takes a fully qualified class name and returns a Class instance for it. This instance can be used to get fields, methods, constructors, and more. Invocation happens with newInstance for constructors and invoke for methods.
- Annotations are a significant part of reflection, primarily targeted towards reflection. They provide meta information accessible at run time to shape the behavior of the program. All important reflection-related types like Class, Field, Constructor, Method, and Parameter implement the AnnotatedElement interface. The getAnnotations method returns the annotations present on that element in form of an array of Annotation instances.
Table of Contents
A language that is capable of reflection, like Java is, allows developers to inspect types, methods, fields, annotations, etc. at run time and to defer the decision on how to use them from compile time to run time. To that end, Java’s reflection API offers types like Class
, Field
, Constructor
, Method
, Annotation
, and others. With them it is possible to interact with types that were not known at compile time, for example to create instances of an unknown class and call methods on them.
This quick tip is intended to give you a high-level understanding of what reflection is, what it looks like in Java, and what it could be used for. After it you will be ready to get started or work through longer tutorials. To get the most out of it you should have a good understanding of how Java is structured, specifically what classes and methods are and how they relate. Knowing about annotations unlocks a separate section.
Reflection API
Instead of building from the ground up I want to start with a simple example. First as plain Java code:
URL url = new URL("https://sitepoint.com/java");
String urlString = url.toExternalForm();
System.out.println(urlString);
I decided at compile time (meaning, when I was writing the code) that I wanted to create an URL
object, and call some method in it. Here’s how I would do the same with Java’s reflection API:
// the gateway to reflection is the `Class` instance
// for the class you want to operate on
Class<?> type = Class.forName("java.net.URL");
// fetches the constructor that takes a `String` argument
// and uses it to create a new instance for the given string
Constructor<?> constructor = type.getConstructor(String.class);
Object instance = constructor.newInstance("https://sitepoint.com/java");
// fetches the `toExternalForm` method and invokes it on
// the instance that was just created
Method method = type.getMethod("toExternalForm");
Object methodCallResult = method.invoke(instance);
System.out.println(methodCallResult);
Using the reflection API is of course more cumbersome than writing the code directly. But this way, details that used to be baked into the code (like that I use URL
or which method I call) becomes just a parameter. As a consequence, instead of having to settle on URL
and toExternalForm
at compile time, they could be decided upon later when the program is already running.
Most use cases for this occur in “frameworky” environments. Think about JUnit, for example, that wants to execute all methods that are annotated with @Test
. Once it found them with a class path scan it uses getMethod
and invoke
to call them. Spring and other web frameworks act similarly when looking for controllers and request mappings. Extensible applications that want to load user-provided plugins at run time are another use case.
Fundamental Types and Methods
The gateway into the reflection API is Class::forName
. In its simple form this static method just takes a fully qualified class name and returns a Class
instance for it. That instance can be used to get fields, methods, constructors, and more.
To get a specific constructor, the getConstructor
method can be called with the types of the constructor arguments as I have done above. Similarly, specific methods can be accessed by calling getMethod
and passing its name as well as the parameter types. The getMethod("toExternalForm")
call above did not specify any types because the method has no arguments.
Here’s a method that does:
Class<?> type = Class.forName("java.net.URL");
// `URL::openConnection` has an overload that accepts a java.net.Proxy
Method openConnection = type.getMethod("openConnection", Proxy.class);
The instances returned by these calls are of type Constructor
and Method
, respectively. To call the underlying member they offer methods like Constructor::newInstance
and Method::invoke
. An interesting detail of the latter is that the instance on which the method is to be called needs to be passed to it as the first argument. The other arguments will be passed on to the called method.
Continuing the openConnection
example:
openConnection.invoke(instance, someProxy);
If a static method is to be called, the instance argument will be ignored and can hence be null
.
Annotations
Annotations are an important part of reflection. In fact, annotations are primarily targeted towards reflection. They are meant to provide meta information that can be accessed at run time and then used to shape the behavior of the program. (As mentioned, JUnit’s @Test
and Spring’s @Controller
and @RequestMapping
are great examples.)
All important reflection related types like Class
, Field
, Constructor
, Method
, and Parameter
implement the AnnotatedElement
interface. The linked Javadoc contains a thorough explanation of how annotations can relate to these elements (directly present, indirectly present, or associated) but it’s simplest form is this: The getAnnotations
method returns the annotations present on that element in form of an array of Annotation
instances, whose members can then be accessed.
Summary
Java’s reflection API allows the introspection of types, methods, annotations, etc. at run time and the invocation of constructors and methods that were not known at compile time. To get started, call Class.forName("fully.qualified.class.Name")
and then getConstructors
, getMethods
, getAnnotations
, or similar methods. Invocation happens with newInstance
for constructors and invoke
for methods.
You can also use reflection to break into code and mutate non-public fields or call non-public methods – this is a risky practice, though, and gets even tougher to pull off in Java 9. If you’re curious and would like to know all the API’s ins and outs, give the reflection trail in Java’s official documentation a go. By now, the API is a little dated and has some downsides but newer alternatives exist, check out method handles (since Java 7) and variable handles (since Java 9).
Frequently Asked Questions (FAQs) about Java Reflection API
What is the main purpose of using Java Reflection API?
The Java Reflection API is a powerful tool that allows you to inspect and manipulate the properties of classes, interfaces, fields, and methods at runtime. This means you can create, inspect, and invoke objects and methods dynamically, without knowing their names at compile time. It’s particularly useful in situations where you need to interact with third-party libraries or legacy code, where the structure might not be known in advance.
Is Java Reflection API slow?
Yes, the Java Reflection API is generally slower than direct code execution. This is because it involves various extra steps such as type checking, method resolution, and security checks. However, the difference in speed is usually negligible unless you’re using reflection in performance-critical sections of your code.
Can Java Reflection API access private fields and methods?
Yes, the Java Reflection API can access private fields and methods. However, this is generally discouraged as it can break encapsulation and lead to code that is difficult to maintain and debug. It’s recommended to use reflection responsibly and only when necessary.
How can I use Java Reflection API to call a method dynamically?
To call a method dynamically using the Java Reflection API, you first need to obtain a Method object representing the method you want to call. You can do this using the getMethod() or getDeclaredMethod() methods of the Class class. Once you have the Method object, you can call its invoke() method, passing in the object you want to call the method on and any arguments.
What is the difference between getMethod() and getDeclaredMethod() in Java Reflection API?
The getMethod() method returns a Method object that represents a public method of the class or interface, including inherited methods. On the other hand, the getDeclaredMethod() method returns a Method object that represents a method of the class or interface, regardless of its access level, but does not include inherited methods.
Can Java Reflection API be used to create arrays?
Yes, the Java Reflection API provides the Array class for creating and manipulating arrays. You can create a new array using the Array.newInstance() method, and you can get or set the value of an array element using the Array.get() and Array.set() methods.
What is the role of the Modifier class in Java Reflection API?
The Modifier class provides static methods and constants to decode and inspect the access modifiers of classes, fields, and methods. For example, you can use the Modifier.isPublic() method to check if a field or method is public.
How can I use Java Reflection API to inspect a class’s constructors?
You can use the getConstructors() or getDeclaredConstructors() methods of the Class class to get an array of Constructor objects representing the constructors of a class. You can then use the methods of the Constructor class to inspect the parameters, exceptions, and modifiers of each constructor.
Can Java Reflection API be used to inspect annotations?
Yes, the Java Reflection API provides methods to inspect annotations at runtime. You can use the getAnnotations() method of the Class, Field, Method, or Constructor class to get an array of Annotation objects representing the annotations of a class, field, method, or constructor.
What are the security implications of using Java Reflection API?
The Java Reflection API can potentially be used to bypass access controls and invoke private methods or access private fields. Therefore, it’s important to use reflection responsibly and ensure that your code does not expose sensitive information or functionality. You should also be aware that the use of reflection can make your code more difficult to understand and maintain.
Nicolai is a thirty year old boy, as the narrator would put it, who has found his passion in software development. He constantly reads, thinks, and writes about it, and codes for a living as well as for fun. Nicolai is the former editor of SitePoint's Java channel, writes The Java 9 Module System with Manning, blogs about software development on codefx.org, and is a long-tail contributor to several open source projects. You can hire him for all kinds of things.