(Turn) Seconds to understand, Java Annotation (Annotation) you can learn this way

Transferred from: Second Understanding, Java Annotation (Annotation) You can learn it like this

Annotations are like labels

Going back to the place where the blog post started, the comments of a news client had the habit of building buildings, so "Jobs redefined the mobile phone, Luo Yonghao redefines the stupid X" often appeared neatly on the comment floor, and the majority of netizens were in the comments section. For quite a long time, I have been very happy with this kind of behavior. This is actually equivalent to the act of labeling. 

In the eyes of some netizens, Luo Yonghao has become synonymous with silly X.

The majority of netizens put a label called "silly x" on Luo Yonghao. They don't really know Luo Yonghao, and they don't know his feats of being a teacher, breaking refrigerators, and running a blog, but because the label of "silly x" exists, there are Help them to evaluate Luo Yonghao directly and quickly, and then based on this, Luo Yonghao can become a talking point after dinner. This is the power of labels. 

On the other side of the Internet, Lao Luo naturally gained a large number of loyal fans by relying on his charisma, and they put another label on Lao Luo.write picture description here

Lao Luo is still Lao Luo, but because people put different labels on it, they have very different views on him. People who don't like him comment on the Internet all day long to criticize and ridicule him, while people who admire and appreciate him are willing to make money. Buy tickets for the launch event of the Hammer Phone.

It is not my intention to evaluate either of these behaviors, and I will cite another example.

"Wonderful Flowers" is a very popular debate program on the Internet in recent years, in which the debater Chen Ming was attacked by another debater Ma Weiwei and said that it was——"Standing in the center of the universe and calling for love", and then put a big label—— ——"Chicken Soup Man", since then, when the audience sees Chen Ming again, the first thing that comes to mind is the three characters "Chicken Soup Man". In fact, Chen Ming is very good in himself. , talk and behave appropriately, but in the Internet, because of the entertainment-oriented environment, people are more willing to understand everything with an entertainment mentality, so "chicken soup man" has become an inseparable label as Chen Ming himself said. 

We can abstractly generalize that a label is an evaluation and explanation of some angle of the behavior of a thing. 

At this point, we can finally draw the protagonist's annotations of this article. 

Beginners can understand annotations like this: imagine that code has life, and annotations are a label attached to some vivid individuals in the code. In short, an annotation is like a label.

Before learning any specific syntax for annotations, you can think of annotations as a label. This helps you quickly understand what it generally does. If a beginner has an empty mind during the learning process, please don't panic and say to yourself:

Annotation, label. Annotation, label. 

Annotation syntax

Because the usual development is rare, I believe that many people will think that the status of annotations is not high. In fact, like classes and interfaces, annotations also belong to a type. It is a concept introduced in Java SE 5.0 release.

Definition of Annotation

Annotations are defined with the @interfacekeyword .

public @interface TestAnnotation {
}

Its form is very similar to that of an interface, but an @ sign is added in front. The above code creates an annotation named TestAnnotaion.

You can simply understand that a label named TestAnnotation is created.

Application of annotations

An annotation is created above, so what is the usage of the annotation.

@TestAnnotation
public class Test { }

 

Create a class Test, and then add @TestAnnotation to the class definition to annotate the class with TestAnnotation.

You can simply understand that the label TestAnnotation is attached to the Test class. 

However, in order for annotations to work properly, there is a new concept that needs to be introduced and that is meta-annotations.

meta-annotation

What do meta-annotations mean?

A meta-annotation is an annotation that can be annotated on an annotation, or a meta-annotation is a basic annotation, but it can be applied to other annotations. 

If it is difficult to understand, you can understand it this way. A meta-annotation is also a tag, but it is a special tag whose function and purpose is to explain other common tags.

There are five types of meta tags: @Retention, @Documented, @Target, @Inherited, and @Repeatable.

@Retention

Retention in English means retention period. When @Retention is applied to an annotation, it interprets the lifetime of the annotation.

Its values ​​are as follows: - The RetentionPolicy.SOURCE annotation is only retained in the source code stage, and it will be discarded and ignored when the compiler compiles. - The RetentionPolicy.CLASS annotation is only retained until compilation, it is not loaded into the JVM. - RetentionPolicy.RUNTIME annotations can be retained until the program is running, it will be loaded into the JVM, so they can be obtained when the program is running. 

We can deepen our understanding in this way. When @Retention explains a label, it specifies the time when the label is posted. @Retention is equivalent to stamping a timestamp on a label, and the timestamp indicates the time period in which the label was posted.

@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation { }

In the above code, we specify that TestAnnotation can be obtained during the program running cycle, so its life cycle is very long. 

@Documented

As the name suggests, this meta-annotation is definitely related to the document. Its role is to be able to include the elements in the annotation into the Javadoc.

@Target

Target means the target, and @Target specifies where the annotation is used. 

You can understand it this way, when an annotation is annotated with @Target, the annotation is limited to the application scenarios.

Analogy to the label, the original label is where you want to post it, but because of the existence of @Target, the place where it is posted is very specific, for example, 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 constructors
  • ElementType.FIELD can annotate properties
  • ElementType.LOCAL_VARIABLE can annotate local variables
  • ElementType.METHOD can annotate methods
  • ElementType.PACKAGE can annotate a package
  • ElementType.PARAMETER can annotate parameters within a method
  • ElementType.TYPE can annotate a type, such as class, interface, 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 an annotation annotated by @Inherited, then if its subclass is not applied by any annotation, then the subclass The class inherits the annotations of the superclass. It's rather abstract. code to explain.

@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 like this:

Lao Tzu is very rich, so people label him rich. 

When Lao Tzu's son grows up, as long as he doesn't cut off the father-son relationship with Lao Tzu, he is naturally a rich man even though no one else labels him.

Lao Tzu's grandson grows up and is naturally rich. 

This is what people call the rich generation, the second generation, and the third generation. Although the names are different, it seems that there are many labels, but in fact the essence of the matter is that they have a common label, which is the label of the rich man on Lao Tzu.

@Repeatable

Repeatable naturally means repeatable. @Repeatable was added in Java 1.8, so it is a new feature. 

What kind of annotation will be applied multiple times? Usually, the value of the annotation can take multiple values ​​at the same time.

For example, a person 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{ } 

Notice in the code above that @Repeatable annotates Person. The class in parentheses after @Repeatable is equivalent to a container annotation. 

What are container annotations? This is where other annotations are stored. It is also an annotation in itself.

Let's look at the relevant container annotations in the code again.

@interface Persons {
    Person[]  value();
}

 

According to the regulations, it must have a value attribute in it, and the attribute type is an annotation array annotated with @Repeatable. Note that it is an array. 

If it is difficult to understand, you can understand it like this. Persons is a general label filled with labels of the same type but different content like Person. Putting Persons on a SuperMan is equivalent to labeling him programmers, product managers, and painters at the same time. 

We may be interested in the content in the brackets of @Person(role=”PM”), which is actually assigning the role attribute of the Person annotation to PM. If you don’t understand it, we will talk about the attribute of the annotation immediately.

Annotated properties

Annotated properties are also called member variables. Annotations only have member variables, not methods. The member variable of the 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 that TestAnnotation has two attributes, id and msg. When using, we should assign values ​​to them.

The way of assignment is in the form of value=”” in the parentheses of the annotation, and it is used before multiple attributes to separate them. 

@TestAnnotation(id=3,msg="hello annotation")
public class Test { }

It should be noted that when defining a property in an annotation, its type must be 8 basic data types plus classes, interfaces, annotations and their arrays. 

Attributes in annotations can have default values, and the default value 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 the id attribute in TestAnnotation is -1, and the default value of the msg attribute is Hi. It can be applied like this.

@TestAnnotation()
public class Test {}

 

Because there is a default value, there is no need to assign values ​​in the parentheses after @TestAnnotation, and this step can be omitted. 

Also, 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 like this.

@Check("hi")
int a;

 

This has the same effect as the following

@Check(value="hi")
int a;

 

Finally, one more thing to be aware of is when an annotation doesn't have any attributes. for example

public @interface Perform {}

 

Then when applying this annotation, the parentheses can be omitted.

@Perform
public void testMethod(){}

 

Java preset annotations

After learning the relevant knowledge above, we can already 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 encountered frequently in daily development. When the compiler encounters this annotation during the compilation phase, it will issue a warning warning, telling the developer that an obsolete element is being called, such as an obsolete method, an obsolete class, and an obsolete 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 with two methods say() and speak(), where say() is annotated with @Deprecated. Then we call them individually in the IDE.write picture description here

As you can see, the say() method is drawn with a straight line, which is actually the reminder effect after the compiler recognizes it.

@Override

This should be familiar to everyone, prompting the subclass to override the method modified by @Override in the parent class

@SuppressWarnings

Prevent the meaning of the warning. As mentioned earlier, after calling a method annotated with @Deprecated, the compiler will warn you, and sometimes developers ignore this warning, and they can achieve their purpose through @SuppressWarnings where they are called.

@SuppressWarnings("deprecation")
public void test1(){ Hero hero = new Hero(); hero.say(); hero.speak(); }

 

@SafeVarargs

Parameter safe type annotations. Its purpose is to remind developers not to do some unsafe operations with parameters, and its existence will prevent the compiler from generating warnings like unchecked. It was added in the Java 1.7 release.

@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 during the compilation phase, but the exception of ClassCastException will be thrown at runtime, so although it tells the developer to handle it properly, the developer himself screwed up. 

The official Java documentation says that a future version will authorize the compiler to generate false warnings for such unsafe operations. 

@FunctionalInterface

Functional interface annotations, a new feature introduced in Java 1.8. Functional programming is hot, so Java 8 added it just in time.

A functional interface is a normal interface with one method.

for example

@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(); } 

The Runnable commonly used in thread development is a typical functional interface. As you can see from the source code above, it is annotated by @FunctionalInterface. 

One might wonder, what is the use of functional interface tags, the reason is that functional interfaces can be easily converted into lambda expressions. This is another topic. Interested students please search for relevant knowledge points to learn.

Annotation extraction

The previous part of the blog post covered the basic syntax of annotations, now it's time to test what we've learned. 

I use tags to compare annotations. The previous content is about how to write annotations and where to paste them. Now what we need to do is to review the content of these tags. The image metaphor is that you tear off these annotation labels at the appropriate time, and then review the content information above.

In order to properly review annotations, there is one method that is inseparable, and that is reflection. 

Annotations and reflections.

Annotations are obtained through reflection. First, you can use the isAnnotationPresent() method of the Class object to determine whether it has applied an annotation

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 an annotation of the specified type, and the latter method returns all annotations annotated to this element.

If the obtained Annotation is not null, their property methods can be called. for example

@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 result of running the program is:

id:-1
msg:

 

This is the default value of id and msg in TestAnnotation. 

In the above example, only the annotations of the annotations on the class are reviewed, in fact, the annotations on the attributes and methods are still possible. The same is still necessary to fake the reflex. 

@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); //获取类的注解 System.out.println("id:"+testAnnotation.id()); System.out.println("msg:"+testAnnotation.msg()); } try { Field a = Test.class.getDeclaredField("a"); a.setAccessible(true); //获取一个成员变量上的注解 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 ) { // 获取方法中的注解 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.

Annotation usage scenarios

I believe that everyone is familiar with annotations in the blog post, but many students will definitely ask, what is the use of annotations? 

So what's the use of annotations? 

We might as well turn our attention to the official Java documentation. 

At the beginning of the article, I used tags as an analogy to annotations. But the label metaphor is my means, not the end. The purpose is to let everyone not be confused by those abstract new concepts when they first learn annotations. Now that we know something about annotations, we might as well read the most rigorous official documentation again.

Annotations are sets of metadata that provide data for interpreting program code, but are not part of the interpreted code itself. Annotations have no direct effect on how the code works. 

Annotations have many uses, mainly as follows: - Provide information to the compiler: Compilers can use annotations to detect errors and warnings - Compilation-time processing: Software tools can use annotation information to generate code, Html documents, or other Treat accordingly. - Runtime processing: some annotations can accept code extraction when the program is running 

It's worth noting that annotations are not part of the code itself.

If it's hard to understand, look at it this way. Luo Yonghao is still Luo Yonghao, it will not change because of some people's "stupid x" evaluation of him, the label is only some people's evaluation of other things, but the label will not change the thing itself, the label is only a means for a specific group of people. Therefore, annotations also cannot change the code itself, and annotations are only tools for certain tools.

Going back to the explanation of the official documentation, the annotations are mainly aimed at compilers and other software tools (SoftWare tools).

When the developer uses Annotation to modify the class, method, Field and other members, these Annotations will not take effect by themselves, and the developer must provide the corresponding code to extract and process the Annotation information. These codes for processing extraction and processing Annotation are collectively referred to as APT (Annotation Processing Tool). 

Now that we can give ourselves the answer, what's the use of annotations? Who is it for? For the compiler or APT.

If you still haven't figured it out, I'll write one myself.

Customize annotations by hand to complete a purpose

I'm going to write a test framework that tests programmers' code for obvious exceptions. 

- Programmer A: I wrote a class, its name is NoBug, because all its methods are bug-free. - Me: Confidence is a good thing, but in order to prevent accidents, how about let me test it? —— Programmer A: How to test? - Me: Just add the @Jiecha annotation to all the methods of the code you write. - Programmer A: OK. 

NoBug.java

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("我写的程序没有 bug!"); } }

In the above code, some methods are annotated with @Jiecha.

This annotation is the annotation 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 method 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(); //用来记录测试产生的 log 信息 StringBuilder log = new StringBuilder(); // 记录异常的次数 int errornum = 0; for ( Method m: method ) { // 只有被 @Jiecha 标注过的方法才进行测试 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 "); //记录测试过程中,发生的异常的名称 log.append(e.getCause().getClass().getSimpleName()); log.append("\n\r"); //记录测试过程中,发生的异常的具体信息 log.append(e.getCause().getMessage()); log.append("\n\r"); } } } log.append(clazz.getSimpleName()); log.append(" has "); log.append(errornum); log.append(" error."); // 生成测试报告 System.out.println(log.toString()); } } 

The result of the test is:

1234567890
1+1=11
1-1=0 3 x 5=15 chufa has error: caused by ArithmeticException / by zero NoBug has 1 error. 

Prompt that there is an exception in the chufa() method in the NoBug class. The name of this exception is ArithmeticException. The reason is that the operation of dividing by 0 is performed during the operation.

So, NoBug This class has bugs. 

In this way, through annotations, I accomplish my own purpose, which is to test other people's code. 

So, ask me when to use annotations? I can only tell you, it depends on what you want to use it for.

Annotation application example

There are too many places where annotations are used, because I am an Android developer, so the specific examples I have come into contact with are as follows:

JUnit

JUnit is a testing framework, typically used as follows:

public class ExampleUnitTest {
    @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } }

@Test marks the method addition_isCorrect() to be tested. 

ButterKnife

ButterKnife is a well-known IOC framework in Android development, which reduces a lot of repetitive code.

public class MainActivity extends AppCompatActivity { @BindView(R.id.tv_test) TextView mTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); } } 

Dagger2

It is also a well-known dependency injection framework. 

Retrofit

Very awesome Http network access framework

public interface GitHubService {
  @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class); 

Of course, there are many places where annotations are applied, so I won't list them all here. 

Summarize

  1. If a comment is hard to understand, you can use it as a label. Labels are meant to explain things, and comments are meant to explain code.
  2. The basic syntax of annotation, creation is like interface, but with an @ symbol.
  3. The meta-annotation of the annotation.
  4. Annotated properties.
  5. Annotations are mainly used by compilers and tool-type software.
  6. The extraction of annotations requires the help of Java's reflection technology, which is relatively slow, so it is necessary to carefully consider the time cost when using annotations.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325367865&siteId=291194637