Annotations and Reflection
Metadata and code that can inspect code
Sometimes a program needs more than the values stored in objects. It may need to know how a developer marked a class or method, which fields and constructors a type has, or which method should be called when its name becomes known only at runtime. Java provides two closely related mechanisms for such tasks: annotations and reflection.
Annotations add metadata to a program — information about the code. Reflection makes it possible at runtime to obtain descriptions of classes and their members, read available annotations, and, when it is actually necessary, dynamically access a field, method, or constructor. A great deal of infrastructure code and many frameworks are built on this combination.
What this section covers
- Annotation Basics. We will see what a notation such as
@Overrideactually means and who can use that metadata. - Built-in Annotations. We will look at annotations that already exist in Java and the problems they solve in ordinary code.
- Custom Annotations. We will learn to describe our own markers and pass values through them.
- Retention and Target. We will define how long an annotation should be preserved and which program elements it may be applied to.
- Reflection Basics. We will get acquainted with
Classas the entry point to a runtime description of a type. - Class, Fields, and Methods. We will learn to obtain information about fields, methods, and constructors and distinguish declared members from inherited ones.
- Dynamic Access with Reflection. We will see how reflection can read values, create objects, and invoke methods when a specific member is selected at runtime.
- Reflection Limitations and Considerations. We will examine where this dynamism helps and where it weakens type safety, maintainability, and encapsulation boundaries.
First, we will learn to leave metadata in code, then control where it is valid and how long it exists. After that, we will move to the mechanism that can inspect a type's structure at runtime, and finish with the rules for using that flexibility safely.
@Deprecated
class OldService {
}
Class<OldService> type = OldService.class;
This small example already shows both sides of the section: the class is marked with metadata,
and the Class object represents that type at runtime.
Next, we will examine each part separately.