Talking about java annotations <the most easy-to-understand annotations>

Foreword: The meaning of Annotation in Chinese.

Java annotations are used to provide metadata for Java code.

Metadata refers to the data used to describe data, which, in general, describes the relationship between codes or the internal relationship between codes and other resources (such as database tables). In some technical frameworks, such as Struts and hibernate, metadata is unknowingly used. For Struts, metadata refers to struts-config.xml; for hibernate, it refers to hbm files. The metadata described above are based on XML files or other forms of separate configuration files. This means that there are some inconveniences. 1. Separation from the described files is not conducive to the maintenance of consistency; 2. All such files are ASCII files without explicit type support. Based on the extensive use of metadata, JDK 5.0 introduces the concept of Annotation to describe metadata. In Java, metadata exists in Java code in the form of tags. The existence of metadata tags does not affect the compilation and execution of program code. In short, in short, annotations are what labels mean.

How to create annotations?

After JDK 5.0 came out, there were four types in Java language, namely class, enum, interface and annotation. @interface They are at the same level, and Java represents metadata through annotations.

package OSChina.ClientNew;

public @interface MyAnnotation {
    // Define common final static attributes
    int age = 25;

    // Defining common abstract methods
    String name();
}

Java annotations are essentially interfaces, which inherit Annotation interfaces.

2. Meta-annotations

Meta-annotations are annotations that can be annotated to annotations, or meta-annotations are basic annotations that can be applied to other annotations.

Metatags include @Retention, @Documented, @Target, @Inherited, @Repeatable.

1,@Retention

Retention

When @Retention is applied to annotations, it explains the life cycle of the annotation.

  • RetentionPolicy.SOURCE annotations are reserved only at the source stage and will be discarded and ignored when compilers compile.
  • The RetentionPolicy.CLASS annotation is reserved for compilation only, and it is not loaded into the JVM.
  • The RetentionPolicy.RUNTIME annotation can be retained until the program runs, and it will be loaded into the JVM.

2,@Documented

As the name implies, this meta-annotation is definitely related to documentation. Its function is to include elements in annotations in Javadoc.

3,@Target

Indicate the use of annotations.

  • ElementType.ANNOTATION_TYPE can annotate a comment
  • ElementType.CONSTRUCTOR annotates the construction method
  • ElementType.FIELD annotates attributes
  • ElementType.LOCAL_VARIABLE annotates local variables
  • ElementType.METHOD annotates methods
  • ElementType.PACKAGE annotates a package
  • ElementType.PARAMETER can annotate parameters in a method
  • ElementType.TYPE can annotate a type, such as classes, interfaces, enumerations

4,@Inherited

lnherited means inheritance.

If a superclass is annotated by @Inherited annotations, then if its subclass is not applied by any annotations, the subclass inherits the annotations of the superclass.

Code instance

package OSChina.ClientNew;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)//Annotations can be saved to run the program and loaded into the JVM
@Target(ElementType.TYPE)//Annotate a type, such as classes, interfaces, enumerations
@Inherited //Annotations work when subclasses inherit parent classes
public @interface Desc {
    enum Color {
        White, Grayish, Yellow
    }

    // The default color is white
    Color c() default Color.White;
}

5,@Repeatable

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

What annotations will be used many times? Usually, the values of annotations can be multiple at the same time.

In life, a person often has multiple identities. How can I use each identity as a commentary?

First declare a Persons class to contain all identities

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)
public   @interface Persons {
	Person[] value();
}

Here @Target declares the scope of Persons annotations, and the parameter ElementType.Type represents a type that can be annotated, such as classes, interfaces, and enumerations.

@ Retention is the effective time for annotations, and RetentionPolicy.RUNTIME is the time when a program runs.

Person annotation:

@Repeatable(Persons.class)
public  @interface Person{
	String role() default "";
}

@ Repeatable brackets are equivalent to containers used to store the annotation content.

Declare a Man class and add some identities to it.

@Person(role="CEO")
@Person(role="husband")
@Person(role="father")
@Person(role="son")
public class Man {
	String name="";
}

Access the annotation in the main method:

public static void main(String[] args) {
    Annotation[] annotations = Man.class.getAnnotations();  
    System.out.println(annotations.length);
    Persons p1=(Persons) annotations[0];
    for(Person t:p1.value()){
        System.out.println(t.role());
    }
}

The output of the following code is the same, but you can first determine whether the corresponding annotations are more rigorous.  

if(Man.class.isAnnotationPresent(Persons.class)) {
    Persons p2=Man.class.getAnnotation(Persons.class);
    for(Person t:p2.value()){
        System.out.println(t.role());
    }
 }

Operation results:

III. Attributes of Annotations

The properties of annotations are also called member variables. Annotations have only member variables and no method. Annotated member variables are declared in the form of "method without parameters" in the definition of annotations. 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();
}

TestAnnotation is defined in the code above. This annotation has two attributes: id and msg. When using it, we should assign values to them.

The way to assign values is to use value="" in parentheses of annotations, separated by multiple attributes.

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

It should be noted that when defining attributes in annotations, their types must be eight basic data types plus classes, interfaces, annotations, and their arrays.

Attributes in annotations can have default values, which need to be specified with default key values. For example:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id() default -1;
    public String msg() default "Maggie Jiang";
}

The default value of id attribute in TestAnnotation is -1, and that of msg attribute is Jiang Shuying.  

It can be applied in this way.

@TestAnnotation()
public class Test {}

Because there are default values, there is no need to assign values in parentheses after @TestAnnotation. This step can be omitted.

In addition, there is another case. If there is only one attribute named value in a comment, the attribute value can be filled in brackets directly when the comment is applied.

public @interface Check {
    String value();
}

In the code above, the Check annotation has only the value attribute. So it can be applied in this way.

@Check("hi")
int a;

This is the same as the following

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

Finally, it should be noted that an annotation has no attributes. such as

public @interface Perform {}

So parentheses can be omitted when applying this annotation.

@Perform
public void testMethod(){}

IV. Annotations for Java Preset

Having learned the above, we can define a comment by ourselves. In fact, the Java language itself has provided several ready-made annotations.

1,@Override

You should be familiar with this, prompting subclasses to override the @Override-modified method in the parent class.

2,@Deprecated

After adding this annotation, it means that this method or class is no longer recommended to use. Deleted lines will appear when calling, but it does not mean that it can not be used, just that it is not recommended because there are better methods to call.

Is it all right to delete it directly?

Because in a project, the project is larger and the code is more, but in the subsequent development process, it may not be very reasonable to implement a previous method. At this time, we need to rewrite a method, and the previous method can not be deleted at will, because it may be called elsewhere, so add this annotation. Just OK!

package OSChina.ClientNew;

import java.util.ArrayList;
import java.util.List;

public class Hero {
    @Deprecated
    public void say(){
        System.out.println("nothing has to say!");
    }
    public void speak(){
        System.out.println("i have a dream!");
    }

    public void  addItems(String item){
        List items =  new  ArrayList();
        items.add(item);
        System.out.println("i am "+items);
    }
}

3,@SuppressWarnings

The meaning of preventing warning.

The purpose of this annotation is to give the compiler an instruction to silence certain warnings within the annotated code element.

Note: There are many parameters in this annotation, so we won't go into details here. If you need to, please Baidu by yourself!

4,@SafeVarargs

Parametric Safety Type Annotation.

Its purpose is to remind developers not to use parameters to do unsafe operations, its existence will prevent the compiler from producing unchecked warnings.

Java compilers report unchecked warnings when declaring constructors or methods with variable parameters of fuzzy types, such as generics. In view of this situation, if the ape determines that the declared constructor and method body has no problem, it can be marked with @SafeVarargs, so that the Java compiler will not report unchecked warning!

Take a look at the @SafeVarargs statement in Java SE:

package java.lang;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}

From the Java source code declaration, we learned that the @SafeVarargs annotation can only be used to mark constructors and methods. Because the reservation policy is declared as RUNTIME, this annotation can take effect at runtime.

@ SafeVarargs annotations can only be used for static or final methods.

Code examples:

The method of generic parameter without annotation:

package OSChina.ClientNew;

public class SafeVarargsAnnotation<S> {
    private S[] args;
    public SafeVarargsAnnotation(S... args){
        this.args = args;
    }
    
    public void loopPrintArgs(S... args){
        for (S arg : args){
            System.out.println(arg);
        }
    }
    
    public final void printSelfArgs(S... args){
        for (S arg : this.args) {
            System.out.println(arg);
        }
    }
    
    public static <T> void loopPrintInfo(T... infos){
        for(T info:infos){
            System.out.println(info);
        }
    }

    public static void main(String[] args) {
        SafeVarargsAnnotation.loopPrintInfo("A","B","C");
    }
}

Correct use of annotations:

package OSChina.ClientNew;

public class SafeVarargsAnnotation<S> {
    private S[] args;
    //The constructor can use the @SafeVarargs tag
    @SafeVarargs
    public SafeVarargsAnnotation(S... args){
        this.args = args;
    }

    //You cannot use @SafeVarargs here because this method is not declared static or final.
    // To suppress unchecked warnings, you can use the @SuppressWarnings annotation
    @SuppressWarnings("unchecked")
    public void loopPrintArgs(S... args){
        for (S arg : args){
            System.out.println(arg);
        }
    }
    //The final method can use the @SafeVarargs tag
    @SafeVarargs
    public final void printSelfArgs(S... args){
        for (S arg : this.args) {
            System.out.println(arg);
        }
    }
    //The static method can use the @SafeVarargs tag
    @SafeVarargs
    public static <T> void loopPrintInfo(T... infos){
        for(T info:infos){
            System.out.println(info);
        }
    }

    public static void main(String[] args) {
        SafeVarargsAnnotation.loopPrintInfo("A","B","C");
    }
}

5,@FunctionalInterface

Java 8 introduces a new annotation @Functional Interface for functional interfaces, which is mainly used for compile-level error checking. With this annotation, when the interface you write does not conform to the definition of functional interfaces, the compiler will report errors.

They are mainly used for Lambda expressions and method references (which can actually be considered Lambda expressions).

For example, a functional interface is defined as follows:

@FunctionalInterface
interface GreetingService 
{
    void sayMessage(String message);
}

A Lambda expression can then be used to represent an implementation of the interface (note: JAVA 8 was usually implemented with anonymous classes before):

GreetingService greetService1 = message -> System.out.println("Hello " + message);

V. Annotation and Reflection

1. Annotations are captured by reflection. First, you can use the isAnnotationPresent() method of the Class object to determine whether it has applied a comment.

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

2. Or 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.

3. Code examples:

(1) When no comment is added:

package OSChina.ClinetNew1.Annotation;

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

No fart!

(2) Add notes

package OSChina.ClinetNew1.Annotation;

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

This is the default value of id and msg in Test Annotation.

The above example just reviews the annotations on classes, but the same is true for the annotations on attributes and methods. Likewise, artificial hands and reflexes are needed.

(3) Notes on attributes and methods:

package OSChina.ClinetNew1.Annotation;

public @interface Check {
    String value();
}
package OSChina.ClinetNew1.Annotation;

public @interface Perform {
}
package OSChina.ClinetNew1.Annotation;

import OSChina.ClientNew.Hero;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

@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 annotations for classes
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            //Get annotations 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 ) {
                // Annotations in acquisition methods
                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());
        }
    }
}

It should be noted that @Retention(RetentionPolicy.RUNTIME) is necessary if an annotation is to be successfully extracted at runtime.

6. Use scenarios of annotations

1. Official Interpretation of Annotations:

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 performance of the code.

2. Annotations have many uses:

Providing information to compilers: Compilers can use annotations to detect errors or warnings

(2) Processing during compilation: Software tools can use annotation information to generate code, HTML documents or other response processing.

(3) Runtime processing: Some annotations can accept code extraction while the program is running.

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

3. There are too many uses of annotations, such as JUnit testing framework, typical usage methods:

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

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

There are also many annotations such as the ssm framework.

7. Examples of application of annotations

package OSChina.ClientNew;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface Desc {
    enum Color {
        White, Grayish, Yellow
    }

    // The default color is white
    Color c() default Color.White;
}

The annotation Desc is preceded by three additional annotations: Retention represents the retention level of the annotation, Target indicates where the annotation can be marked, and @Inherited indicates that the annotation will be automatically inherited.

package OSChina.ClinetNew1;

@Desc(c = Desc.Color.White)
abstract class Bird {
    public abstract Desc.Color getColor();
}
package OSChina.ClinetNew1;

public enum BirdNest {
    Sparrow;
    // Bird reproduction
    public Bird reproduce() {
        Desc bd = Sparrow.class.getAnnotation(Desc.class);
        return bd == null ? new Sparrow() : new Sparrow(bd.c());
    }
}
package OSChina.ClinetNew1;

public class Sparrow extends Bird {
    private Desc.Color color;
    // The default is light grey
    public Sparrow() {
        color = Desc.Color.Grayish;
    }

    // Constructor defines the color of birds
    public Sparrow(Desc.Color _color) {
        color = _color;
    }

    @Override
    public Desc.Color getColor() {
        return color;
    }
}

The above program declares a Bird Abstract class, and annotates the Desc annotation to describe the color of birds is white. Then it writes a Sparrow class, which has two constructors, one is the default constructor, that is, the sparrow we often see is light grey, and the other is the custom sparrow. After that, a nest (factory method model) is defined, which is specially responsible for bird reproduction. Its production method, reproduce, generates sparrows of different colors according to the annotated information of the implementation class. We write a client call with the following code:

public static void main(String[] args) {
    Bird bird = BirdNest.Sparrow.reproduce();
    Desc.Color color = bird.getColor();
    System.out.println("Bird's color is :" + color);
}

What will it print out? Because the factory method mode is adopted, the main problem is which constructor is used to generate bird by. If we look at the subclass Sparrow alone, it has no comment, then the bd variable in the factory method should be null, and the parametric construct should be called! __________

Why is the output white? This is the color we added to the parent class, why? This is because we added the @Inherited annotation to the annotation, which means that as long as we add the annotation @Desc to the parent Bird, all its subclasses will inherit the @Desc annotation from the parent.

Summary

1. Annotations are labels. Annotations are for explaining code.

2. Basic grammar of annotations @interface

3. Meta-annotations of annotations

4. Attributes of Annotations

5. Annotations are mainly for compilers and software of tool type.

6. The extraction of annotations depends on Java's reflection technology, which reflects slowly. Therefore, the time cost of annotations should be carefully calculated.

 

Jiang Shuying talks about Java@directory

Keywords: Programming Java Attribute Struts jvm

Added by jamkelvl on Wed, 24 Jul 2019 06:00:22 +0300