Detailed introduction to the concept of annotations in Java, usage, and case demonstrations, such as custom annotations.
1 the concept of annotations
1.1 What are Annotations?
Java annotations are a form of metadata attached to code that is parsed and used by tools at compile time, run time, and configuration. Annotations do not and cannot affect the actual logic of the code, but only serve as an aid. Meta-annotations are included in the java.lang.annotation package.
1.2 Usefulness of annotations
- Generate documentation. This is the most common and the earliest annotation provided in Java. Common ones are @param@return, etc.
- Track code dependencies and implement alternative profile functionality. For example, spring, Mybatis and other framework dependency injection, future Java development, will be a large number of annotations configuration, has a great use;
- Format checking is done at compile time. If @Override comes before a method, it will be checked at compile time if your method does not override a superclass method.
1.3 Principle of annotations
Annotations are essentially a special interface that inherits annotations, implemented by dynamic proxy classes generated by the Java runtime.
When we get annotations through reflection, we return $Proxy1, the dynamic proxy object generated by the Java runtime. Through a proxy object call custom annotations (interface) method, will eventually call AnnotationInvocationHandler invoke method. This method indexes the corresponding value from the Map memberValues. The source of memberValues is the Java constant pool.
Annotation related internal handling classes are located in the Sun.Reflect.Annotation package.
1.4 Basic Syntax
1.4.1 Annotation type declaration section
Annotations are similar to classes, interfaces, and enumerations in Java, so the declaration syntax is basically the same, except that the keyword @interface is different. On the underlying implementation, all annotations defined automatically inherit the Java lang. The annotation. The annotation interface.
1.4.2 Implementation of annotation types
In our experience with custom classes, the implementation part of a class is nothing more than writing constructs, properties, or methods. However, in a custom annotation, the implementation part can only define one thing: the Annotation Type Element.
Note the following when defining an annotation type element:
- Access modifiers must be public, default to public if not written;
- The type of the element can only be a primitive data type, String, Class, enumeration, annotation type (which reflects the nesting effect of annotations), and a one-dimensional array of the above types.
- The name of the element is generally defined as a noun. If there is only one element in the annotation, give it the name value (for convenience later).
- () is not the place to define method arguments, nor can you define any arguments in parentheses, just a special syntax;
- Default indicates the default value. The value must be of the same type as defined in point 2.
- If there is no default value, it means that the type element must be assigned when the annotation is used later.
As you can see, the syntax for annotation type elements is strange, with attributes (which can be assigned) and methods (enclosed in parentheses). But the design makes sense, as we’ll see in a later section: annotations, once defined, manipulate element types like attributes when used, and element types like methods when parsed.
Common meta-annotations
A very basic definition of a comment consists of just two parts: 1. 2. The type element that the annotation contains.
However, when using JDK built-in annotations, we found that some annotations can only be written on methods (such as @override); Others can be written above classes (such as @deprecated). Of course there are a lot of detailed definitions, so how do you make these definitions? Next comes the meta annotation!
Meta-note: a note that specifically modifies a note. They are specifically designed to better design the details of custom annotations. Meta-annotations are in the java.lang.annotation package.
@Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
Copy the code
The @target annotation is specifically used to specify which Java elements a custom annotation can be applied to. If the same enumeration constant appears multiple times in the @target annotation, this is a compile-time error.
The Target annotation uses an enumerated type to define the following optional parameters:
Public enum ElementType {/** class, Declarations for interfaces (including annotation types) or enumerations */ TYPE, /** declarations for attributes */ FIELD, /** declarations for methods */ METHOD, /** declarations for METHOD forms */ PARAMETER, /** annotation type declaration */ ANNOTATION_TYPE, /** PACKAGE declaration */ PACKAGE}Copy the code
2.2 @ Retention
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }Copy the code
@Retention annotation translated as staying power. This is used to modify the vitality of custom annotations.
The annotation life cycle has three phases:
- Java source file stage;
- Compile to class file stage;
- Run-time phase.
The RetentionPolicy enumeration type is also used to define three phases:
Public enum RetentionPolicy {/** * annotations are ignored by the compiler */ SOURCE, /** * annotations are recorded by the compiler in the class file, but are not retained by the vm at runtime. This is a default behavior */ CLASS, /** * annotations will be recorded by the compiler in the CLASS file, and will be retained by the virtual machine at runtime, So they can be read by reflection to * @ see Java. The lang. Reflect. AnnotatedElement * / RUNTIME}Copy the code
2.3 @ Documented
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
Copy the code
Documented, the @documented annotation is used to specify whether a custom annotation will be generated into a JavaDoc document along with the defined Java file.
2.4 @ Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
Copy the code
@Inherited, when you specify a custom annotation that is written in the declaration part of a parent class, the declaration part of a child class automatically owns the annotation. The @Inherited annotation only works with custom annotations where @target is defined as elementType.type.
2.5 @ the Repeatable
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}
Copy the code
@Repeatable indicates whether the annotation is Repeatable. Repeatable was added in Java 1.8. The argument is the Class of the annotation type, indicating that the annotation can be reused.
2.6 @ Native
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Native {
}
Copy the code
Indicates that the value referenced by a field may come from native code. Java 1.8 was added and is currently used less.
3 Custom annotations
3.1 the basic class
First, define an annotation and a simple Java class for annotation modification:
/** * Target: Indicates that ManAnnotation is qualified to be used on a class, interface, or method. • Documented @target (Value = {elementType.type, ElementType.METHOD}) public @interface ManAnnotation { String name(); int age() default 20; String[] tel(); } public class Student { @ManAnnotation(name = "stu", age = 15, tel = {"111111", "66666", "88888"}) public void learn(int times) { for (int i = 0; i < times; i++) { System.out.println("Start learning"); }}}Copy the code
3.2 Special Syntax
Special Syntax 1:
If the annotation itself does not have an annotation type element, you can omit () when using the annotation and write: @ annotation name. This is equivalent to the standard @ annotation name () syntax.
@Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) @Documented public @interface FirstAnnotation { } // equivalent to @firstannotation () @firstannotation public class JavaBeanCopy the code
Special Syntax 2:
If the annotation itself has only one annotation type element named value, then you can use the @annotation name (annotation value), which is equivalent to the @annotation name (value = annotation value).
@Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) @Documented public @interface ThirdAnnotation { String[] name(); } // equivalent to @thirdannotation (name = {"this is third annotation"}) @thirdannotation (name = "this is third annotation") Public class JavaBean{// omit implementation}Copy the code
Special Usage three:
If an annotation element in an annotation is an array type and only one value is required, the annotation name (type name = type value) can be written as @annotation name (type name = {type value}). This is equivalent to the standard way of writing @annotation name (type name = {type value}).
@Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) @Documented public @interface ThirdAnnotation { String[] name(); } // equivalent to @thirdannotation (name = {"this is third annotation"}) @thirdannotation (name = "this is third annotation") Public class JavaBean{// omit implementation}Copy the code
Special Usage four:
If the @target of an annotation is defined as element. PACKAGE, the annotation is configured in package-info.java, not directly on the PACKAGE code of a class.
Other:
There are three phases of annotation retention: the Java source file phase; Compile to class file stage; Run-time phase. Only when the annotation’s holding power is in the running phase, that is, when the annotation is modified with @Retention(retentionPolicy.runtime), can the annotation be detected at JVM RUNTIME and perform a series of special operations.
3.3 Reflection operation to obtain annotations
Annotations and their class contents can be obtained by reflection. If you don’t know reflection, check out this blog post: An in-depth understanding of Java Reflection and how to use it in super detail
Class<Student> stuClass = student.class; / * access to learn the Method object * / Method learnMethod = stuClass. GetDeclaredMethod (" learn, "int. J class); / * if the method with the annotation type, you get comment * / if (learnMethod. IsAnnotationPresent (ManAnnotation. Class)) { System.out.println(" ManAnnotation is configured on Student! ") ); / / get the elements of the specified type annotation ManAnnotation cherryAnnotation = learnMethod. GetAnnotation (ManAnnotation. Class); System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age() + ", tel: " + cherryAnnotation.tel()[0]); } else {system.out. println(" ManAnnotation is not configured on Student! ") ); }Copy the code
Explain:
If the annotation we want is configured on a Method, we need to get it from the Method object. If configured on a property, it needs to be retrieved from the Field object corresponding to the property. If configured on a type, it needs to be retrieved from the Class object. In a word, on whom, from whom to obtain!
isAnnotationPresent(Class<? The extends Annotation> annotationClass) method determines whether a specified Annotation is configured on the element.
The getAnnotation(Class< T > annotationClass) method gets the annotation specified on the element. The annotation type element method of the annotation can then be called to obtain the value data at configuration time.
There’s also a method getAnnotations() on this reflection object that retrieves any annotations configured on it. It will return us an array of annotations, and notice that the type of the array is the Annotation type, which is an interface from the java.lang. Annotation package.