catalogue
Usage scenarios for annotations
Self defined annotation to achieve a certain purpose
Annotation application example
Definition of annotation
Annotations are defined by the @ interface keyword.
public @interface TestAnnotation { }
Its form is very similar to the interface, but there is an @ symbol in front of it. The above code creates an annotation named testannotation.
It can be simply understood as creating a label named test annotation.
Application of annotation
An annotation is created above. What is the usage of the annotation.
@TestAnnotation public class Test { }
Create a Test class, and then add @ TestAnnotation to the class definition to annotate the class with TestAnnotation.
You can simply understand that the label TestAnnotation is pasted on the Test class.
However, in order for annotations to work properly, we need to introduce a new concept, meta annotation.
Meta annotation
What does meta annotation mean?
Meta annotation is an annotation that can be annotated to annotations, or meta annotation is a basic annotation, but it can be applied to other annotations.
Meta annotation is also a label, but it is a special label. Its function and purpose is to explain other ordinary labels.
Meta tags include @ Retention, @ Documented, @ Target, @ Inherited, @ repeatable.
@Retention
When @ Retention is applied to an annotation, it explains the lifetime of the annotation.
Its values are as follows:
- The RetentionPolicy.SOURCE annotation is reserved only at the source stage and will be discarded and ignored when the compiler compiles.
- The RetentionPolicy.CLASS annotation is only retained until the compilation is in progress, and it will not be loaded into the JVM.
- RetentionPolicy.RUNTIME annotations can be retained until the program runs, and they will be loaded into the JVM, so they can be obtained when the program runs.
We can deepen our understanding in this way. When @ Retention explains a label, it specifies the posting time of the label. @ Retention is equivalent to stamping a label with a time stamp, which indicates the posting time period of the label.
@Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { }
In the above code, we specify that TestAnnotation can be obtained in the program running cycle, so its life cycle is very long.
@Documented
As the name suggests, this meta annotation must be related to the document. Its function is to include the elements in the annotation into the Javadoc.
@Target
Target means target, @ target specifies where annotations are used.
You can understand that when an annotation is annotated by @ Target, the annotation is limited to the application scenario.
By analogy to tags, the original tag is that you can post wherever you want, but because of the existence of @ Target, it can only be posted on methods, classes, method parameters, etc. @ Target has the following values
- ElementType.ANNOTATION_TYPE can annotate an annotation
- ElementType.CONSTRUCTOR can annotate construction methods
- ElementType.FIELD can annotate attributes
- ElementType.LOCAL_VARIABLE can annotate local variables
- ElementType.METHOD can annotate methods
- ElementType.PACKAGE can annotate a package
- ElementType.PARAMETER can annotate parameters in a method
- ElementType.TYPE can annotate a type, such as class, interface and enumeration
@Inherited
Inherited means inheritance, but it does not mean that the annotation itself can be inherited, but that if a superclass is annotated with @ inherited annotation, if its subclass is not applied by any annotation, then the subclass inherits the annotation of the superclass.
It's more abstract. It's explained by code.
@Inherited @Retention(RetentionPolicy.RUNTIME) @interface Test {} @Test public class A {} public class B extends A {}
The annotation Test is modified by @ Inherited, then class A is annotated by Test, class B inherits a, and class B also has the annotation Test.
It can be understood as follows:
This is what people call the rich generation, the rich second generation and the rich third generation. Although they have different names, like many labels, the essence of things is that they have a common label, that is, the label of the rich on Lao Tzu.
@Repeatable
Repeatable naturally means repeatable. @ repeatable is added only in Java 1.8, so it is a new feature.
What kind of annotation will be applied multiple times? Usually, the annotation value can take multiple values at the same time.
For example, a man is both a programmer and a product manager, and he is also a painter.
@interface Persons { Person[] value(); } @Repeatable(Persons.class) @interface Person{ String role default ""; } @Person(role="artist") @Person(role="coder") @Person(role="PM") public class SuperMan{ }
Note that in the above code, @ Repeatable annotates Person. The class in parentheses after @ Repeatable is equivalent to a container annotation.
What is a container annotation? It is the place where other annotations are stored. It is also an annotation itself.
Let's look at the relevant container annotations in the code.
@interface Persons { Person[] value(); }
According to regulations, it must have a value attribute. The attribute type is an annotation array annotated by @ Repeatable. Note that it is an array.
If it is difficult to understand, it can be understood in this way. People is a general label, which is covered with people, which is the same type but different content. Labeling people to a SuperMan is equivalent to labeling him as a programmer, product manager and painter at the same time.
We may be interested in the contents in @ Person(role = "PM") brackets. In fact, it is to assign PM to the role attribute of the annotation of Person. We don't understand that it is normal. Let's talk about the attribute of the annotation right away.
Properties of annotations
The attribute of an annotation is also called a member variable. An annotation has only member variables and no methods. The member variable of an annotation is declared in the form of "method without formal parameters" in the definition of the annotation. Its method name defines the name of the member variable, and its return value defines the type of the member variable.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { int id(); String msg(); }
The above code defines TestAnnotation, which has id and msg attributes. When using, we should assign values to them.
The assignment method is in the form of value = "in the parentheses of the annotation, and multiple attributes are separated by.
@TestAnnotation(id=3,msg="hello annotation") public class Test { }
It should be noted that when defining an attribute in an annotation, its type must be 8 basic data types, plus classes, interfaces, annotations and their arrays.
The attribute in the annotation can have a default value, which needs to be specified with the default key value. For example:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { public int id() default -1; public String msg() default "Hi"; }
The default value of id attribute in TestAnnotation is - 1, and the default value of msg attribute is Hi.
It can be applied in this way.
@TestAnnotation() public class Test {}
Because there are default values, there is no need to assign values in the brackets after @ TestAnnotation. This step can be omitted.
In addition, there is another situation. If there is only one attribute named value in an annotation, the attribute value can be directly filled in parentheses when applying this annotation.
public @interface Check { String value(); }
In the above code, the Check annotation only has the value attribute. So it can be applied in this way.
@Check("hi") int a;
This is the same as the following effect
@Check(value="hi") int a;
Finally, you should also note that an annotation does not have any attributes. such as
public @interface Perform {}
Then the parentheses can be omitted when applying this annotation.
@Perform public void testMethod(){}
Annotations for Java presets
After learning the above knowledge, we can define an annotation by ourselves. In fact, the Java language itself already provides several ready-made annotations.
@Deprecated
This element is used to mark outdated elements, which must be often encountered in daily development. When the compiler encounters this annotation at the compilation stage, it will issue a warning to tell the developer that an outdated element is being called, such as an outdated method, an outdated class, and an outdated member variable.
public class Hero { @Deprecated public void say(){ System.out.println("Noting has to say!"); } public void speak(){ System.out.println("I have a dream!"); } }
A Hero class is defined, which has two methods say() and speak(), where say() is annotated by @ Deprecated. Then we call them separately in the IDE.
You can see that the say() method is marked by a straight line, which is actually the reminder effect after the compiler recognizes it.
@Override
You should be familiar with this. It prompts the subclass to copy the method modified by @ Override in the parent class
@SuppressWarnings
Stop the meaning of the warning. As mentioned earlier, after calling the @ Deprecated annotated method, the compiler will warn, and sometimes developers will ignore this warning. They can achieve the purpose through @ SuppressWarnings at the place of call.
@SuppressWarnings("deprecation") public void test1(){ Hero hero = new Hero(); hero.say(); hero.speak(); }
@SafeVarargs
Parameter security type annotation. Its purpose is to remind developers not to use parameters to do some unsafe operations. Its existence will prevent the compiler from generating warnings such as unchecked. It is added in the version of Java 1.7.
@SafeVarargs // Not actually safe! static void m(List<String>... stringLists) { Object[] array = stringLists; List<Integer> tmpList = Arrays.asList(42); array[0] = tmpList; // Semantically invalid, but compiles without warnings String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime! }
In the above code, no error will be reported at the compilation stage, but the exception ClassCastException will be thrown at runtime, so although it tells the developer to handle it properly, the developer still screwed up.
Java official documents say that future versions will authorize the compiler to generate error warnings for such unsafe operations.
@FunctionalInterface
Functional interface annotation, a new feature introduced in Java version 1.8. Functional programming is very popular, so Java 8 has added this feature in time.
Functional interface is a common interface with one method.
such as
@FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
Runnable, which is commonly used in thread development, is a typical functional interface. As you can see from the above source code, it is annotated by @ functional interface.
Some people may wonder what the use of functional interface tags is because functional interfaces can be easily converted to Lambda expressions. This is another topic. If you are interested, please search for relevant knowledge points by yourself.
Annotation extraction
The previous part of the blog talked about the basic syntax of annotation. Now it's time to test what we have learned.
I compare labels to notes. The previous content is about how to write notes and where to paste them. Now we have to review the contents of these labels. The image metaphor is that you tear off these annotation labels at the right time, and then review the content information on them.
If you want to review annotations correctly, you can't do without a means, that is reflection.
Annotation and reflection
Annotations are obtained by reflection. First, you can determine whether an annotation has been applied by the isAnnotationPresent() method of the Class object
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
Then get the Annotation object through the getAnnotation() method.
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
Or the getAnnotations() method.
public Annotation[] getAnnotations() {}
The former method returns annotations of the specified type, and the latter method returns all annotations annotated on this element.
If the obtained Annotation is not null, their property methods can be called. such as
@TestAnnotation() public class Test { public static void main(String[] args) { boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class); if ( hasAnnotation ) { TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class); System.out.println("id:"+testAnnotation.id()); System.out.println("msg:"+testAnnotation.msg()); } } }
The running result of the program is:
id:-1 msg:
This is the default value of id and msg in test annotation.
In the above example, only the annotations on the class are reviewed. In fact, the annotations on attributes and methods are still OK. Also, the artificial hand should be reflected.
@TestAnnotation(msg="hello") public class Test { @Check(value="hi") int a; @Perform public void testMethod(){} @SuppressWarnings("deprecation") public void test1(){ Hero hero = new Hero(); hero.say(); hero.speak(); } public static void main(String[] args) { boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class); if ( hasAnnotation ) { TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class); //Get class annotations System.out.println("id:"+testAnnotation.id()); System.out.println("msg:"+testAnnotation.msg()); } try { Field a = Test.class.getDeclaredField("a"); a.setAccessible(true); //Gets the annotation on a member variable Check check = a.getAnnotation(Check.class); if ( check != null ) { System.out.println("check value:"+check.value()); } Method testMethod = Test.class.getDeclaredMethod("testMethod"); if ( testMethod != null ) { // Get annotation in method Annotation[] ans = testMethod.getAnnotations(); for( int i = 0;i < ans.length;i++) { System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName()); } } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(e.getMessage()); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(e.getMessage()); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println(e.getMessage()); } } }
Their results are as follows:
id:-1 msg:hello check value:hi method testMethod annotation:Perform
It should be noted that @ Retention(RetentionPolicy.RUNTIME) is required if an annotation is to be successfully extracted at runtime.
Usage scenarios for annotations
I believe we are all familiar with annotation here, but many students will certainly ask, what is the use of annotation?
Yeah, what's the use of annotations?
We might as well focus on the official Java documentation.
At the beginning of the article, I used tags to compare notes. But the label metaphor is only my means, not my end. The purpose is to let everyone not be confused by those abstract new concepts when learning annotations for the first time. Now that we know something about annotations, we might as well read the most rigorous official documents carefully.
Annotations are a series of metadata that provide data to interpret program code, but annotations are not part of the interpreted code itself. Annotations have no direct impact on the running effect of the code.
Annotations have many uses, mainly as follows:
- Provide information to the compiler: the compiler can use annotations to detect errors and warnings
- Compilation stage processing: software tools can be used to generate code, Html documents or other corresponding processing by using annotation information.
- Runtime processing: some annotations can accept code extraction when the program is running
It is worth noting that annotations are not part of the code itself.
Labels are just some people's evaluation of other things, but labels will not change the things themselves. Labels are only a means for specific people. Therefore, annotations also cannot change the code itself. Annotations are just tools of some tools.
Back to the explanation of the official documents, the annotations are mainly aimed at compilers and other software tools.
After the developer modifies the class, method, Field and other members with annotations, these annotations will not take effect by themselves. The developer must provide corresponding code to extract and process the Annotation information. These codes for extracting and processing annotations are collectively referred to as APT (Annotation Processing Tool).
Now, we can give ourselves the answer. What's the use of annotations? For whom? For the compiler or APT.
If you still don't understand, I'll write one myself.
Self defined annotation to achieve a certain purpose
I want to write a test framework to test the programmer's code for obvious exceptions.
——Programmer A: I wrote A class called NoBug because all its methods have no errors.
——Me: confidence is a good thing, but in order to prevent accidents, let me test it?
——Programmer A: how to test?
——Me: just add @ Jiecha annotation to the methods of your code.
——Programmer A: OK.
package ceshi; import ceshi.Jiecha; public class NoBug { @Jiecha public void suanShu(){ System.out.println("1234567890"); } @Jiecha public void jiafa(){ System.out.println("1+1="+1+1); } @Jiecha public void jiefa(){ System.out.println("1-1="+(1-1)); } @Jiecha public void chengfa(){ System.out.println("3 x 5="+ 3*5); } @Jiecha public void chufa(){ System.out.println("6 / 0="+ 6 / 0); } public void ziwojieshao(){ System.out.println("I didn't write the program bug!"); } }
In the above code, some methods use @ Jiecha annotation.
This annotation is defined in the test software framework I wrote.
package ceshi; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Jiecha { }
Then, I write a test class TestTool to test the corresponding methods of NoBug.
package ceshi; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestTool { public static void main(String[] args) { // TODO Auto-generated method stub NoBug testobj = new NoBug(); Class clazz = testobj.getClass(); Method[] method = clazz.getDeclaredMethods(); //It is used to record the log information generated by the test StringBuilder log = new StringBuilder(); // Record the number of exceptions int errornum = 0; for ( Method m: method ) { // Only the methods marked by @ Jiecha can be tested if ( m.isAnnotationPresent( Jiecha.class )) { try { m.setAccessible(true); m.invoke(testobj, null); } catch (Exception e) { // TODO Auto-generated catch block //e.printStackTrace(); errornum++; log.append(m.getName()); log.append(" "); log.append("has error:"); log.append("\n\r caused by "); //Record the name of the exception that occurred during the test log.append(e.getCause().getClass().getSimpleName()); log.append("\n\r"); //Record the specific information of exceptions during the test log.append(e.getCause().getMessage()); log.append("\n\r"); } } } log.append(clazz.getSimpleName()); log.append(" has "); log.append(errornum); log.append(" error."); // Generate test report System.out.println(log.toString()); } }
The test results are:
1234567890 1+1=11 1-1=0 3 x 5=15 chufa has error: caused by ArithmeticException / by zero NoBug has 1 error.
It is suggested that there is an exception in the chufa() method in NoBug class. The exception name is ArithmeticException because the operation of dividing by 0 is carried out during the operation.
Therefore, the NoBug class has a Bug.
In this way, through annotation, I have completed my own purpose, that is, testing other people's code.
So, ask me when the annotation is used? I can only tell you, it depends on what you want to use it for.
Annotation application example
Notes are used in too many places, such as:
JUnit is a testing framework. Typical usage methods are as follows:
public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } }
@Test marks the method to be tested, addition_isCorrect()
For example, ssm framework uses a lot of annotations.
summary
- If the annotation is difficult to understand, you can think of it as a tag. The tag is to explain things and the annotation is to explain code.
- The basic syntax of annotation is like an interface, but there are multiple @ symbols.
- Meta annotation of annotation.
- Properties of the annotation.
- Annotations are mainly used for compiler and tool type software.
- The extraction of annotations needs the help of Java reflection technology, which is slow, so the time cost should be carefully considered when using annotations.