Before learning annotations, I will first talk about the benefits of learning annotations. Whether you read the following or not, just give me some encouragement. However, it is certain that in normal JAVA development, few people write their own annotations. In most cases, they use annotations from third-party libraries. Because of this, most developers only know how to use annotations. Imagine that if you know how to use annotations when most people don’t, then you have surpassed most people. In addition, I also summarize the three major benefits of learning annotations:
- Able to understand code written by others, especially framework-related code;
- Make programming more concise and the code clearer;
- Let others look up to you, a powerful tool for showing off;
Having said all this, let’s start talking about the real stuff.
Annotation Concept
JDK 5 introduced the mechanism of annotation in source code. Annotation allows Java source code to contain not only functional implementation code, but also metadata. The function of annotation is similar to that of comments in code, but the difference is that annotation does not provide a description of the code function, but is an important part of realizing program functions.
Common annotations in Java
For common annotations, you can understand them by just looking at the annotations that pop up in the IDE when developing JAVA. For JDK annotations, we must be very familiar with them.
JDK comes with annotations
@Override
@Deprecated
@Suppvisewarnings
Common third-party annotations
- Spring
@Autowired
@Service
@Repository
- Mybatis
@InsertProvider
@UpdateProvider
@Options
Classification of annotations
Classification by operating mechanism
- Source code annotations (annotations only exist in the source code and are compiled into
.class
will not exist after being compiled into files) - Compile-time annotations (annotations in source code and
.class
exist in both source code and files, the above three JDK annotations are compile-time annotations) - Runtime annotations (annotations that still work during the runtime and even affect the runtime logic, for example
@Autowired
)
Sort by source
- Annotations from JDK
- Notes from third parties
- Custom Annotations
Meta Annotation
Annotations for annotations
Custom Annotations
The following is a typical annotation declaration. Let’s take a look at it first. The following will explain the precautions for defining annotations:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String desc();
String author();
int age() default 18;
}
- use
@interface
Defining annotations - Members (variables) are declared without parameters and without exceptions
- Can use
default
specify a default value for a member - The types of members in annotations are restricted. Legal types include basic data types as well as
String
,Class
,Annotation
andEnumeration
- If the annotation has only one member, the member name should be
value()
, and the member name and assignment number can be omitted when used (=
the member name and assignment sign ( ) - An annotation class can have no members. An annotation without members is called an identification annotation.
- Meta-annotation, used to annotate annotations, such as
Description
the 4 annotations above
Commonly used meta annotations
Target
Identifies the scope of the annotation. The scopes are as follows, covering almost all types of JAVA:
ElementType.CONSTRUCTOR
:Construction methodElementType.FIELD
: FieldElementType.LOCAL_VARIABLE
: Local variablesElementType.METHOD
:methodElementType.PACKAGE
:BagElementType.PARAMETER
: ParametersElementType.TYPE
: Class, Interface
For example, the example above identifies Description
methods and classes or interfaces that can be annotated:
@Target({ElementType.PARAMETER, ElementType.TYPE})
Retention
Identifies the life cycle of an annotation. There are three values:
RetentionPolicy.SOURCE
: Only displayed in source code, discarded during compilationRetentionPolicy.CLASS
: It will be recordedclass
in the file during compilation and ignored during runtimeRetentionPolicy.RUNTIME
: exists at runtime and can be read through reflection
For example, the example above indicates that Description
the data can be recorded to class
a file, but will be ignored at runtime:
@Retention(RetentionPolicy.CLASS)
Inherited
Identifying meta-annotation, indicating that the annotation is allowed to be inherited by subclasses. Note that this is not the inheritance of annotations, nor is there inheritance between annotations. What this means is that if this annotation is used on a class (not an interface) declaration, then when a subclass inherits from this class, it will also have the same annotation as the parent class.
Documented
This annotation will be included when generating JAVA DOC.
Using custom annotations
The syntax for using annotations is:
The member names correspond to the members in the annotation, for example:
@Description(desc="description", author="swifter", age=18)
public String getColor() {
return "red";
}
The above is just a simple example. Here is a detailed usage of annotations, which is also the way used in normal development. For annotations, a declaration has been given in the above code. Here are two classes to use the annotations. Through these two examples, it is obvious how to use annotations.
First class Person
:
@Description(desc="person interface", author="swifter")
public abstract class Person {
@Description(desc="method getName", author="swifter")
abstract String getName();
abstract void doSomething();
}
The second class Child
inherits from Person
:
public class Child extends Person {
@Override
@Description(desc="child method getName", author="swifter")
public String getName() {
return "get child";
}
@Override
public void doSomething() {
System.out.println("do something in child class");
}
}
Parsing Annotations
Now that the annotation has been defined, we should consider how to parse the annotation in the code. Parsing annotations is to obtain the runtime annotation information on the class, function or member through reflection, so as to implement the logic of dynamically controlling the program operation. The main way of parsing is to Class
obtain the annotation through the object through reflection, and then get the annotated field for operation. For example, the following example:
Class<Child> clazz = Child.class;
if(clazz.isAnnotationPresent(Description.class)) {
Description description = clazz.getAnnotation(Description.class);
System.out.println(description.desc()+" : "+description.author());
}
Method[] methods = clazz.getMethods();
for(Method method : methods) {
if(method.isAnnotationPresent(Description.class)) {
Description description = method.getAnnotation(Description.class);
System.out.println(description.desc()+" : "+description.author());
}
}
After running, the client will give the following results:
person interface : swifterchild method getName : swifter
The first line shows the annotation information on the class, and the second line shows the annotation information on the method. As can be seen in the code, both of these annotated objects are obtained through reflection. Although reflection is relatively slow in efficiency, considering the advantages brought by annotations, it is still necessary to master annotations.