The article directories

  • Introduction to the
  • Definition and use of annotations
  • Yuan notes
    • @Retention
    • @Documented
    • @Target
    • @Inherited
    • @Repeatable
  • Attributes of annotations
  • Java preconfigured annotations
    • @Deprecated
    • @Override
    • @SuppressWarnings
    • @SafeVarargs
    • @FunctionalInterface
  • Annotations and reflections
    • Annotations on a class
    • Annotations on properties and methods
  • Usage scenarios for annotations
  • chestnuts
  • Annotation Application Example
    • JUnit
    • ButterKnife

Introduction to the

Annotation is a very important knowledge in Java, beginners can understand Annotation: imagine code is alive, Annotation is a label attached to some living individual in the code. In a nutshell, a annotation is like a label

Because the common development is rare, I believe that many people will think that the status of annotations is not high. Annotations are a type, just like class and interface. It was introduced in Java SE 5.0

Definition and use of annotations

Annotations are defined by the @interface keyword

public @interface TestAnnotation {
}
Copy the code

It looks like an interface, but with an @ sign in front of it. The above code creates an annotation named TestAnnotaion

Now that you have created an annotation, what is the usage of the annotation

@TestAnnotation
public class Test {}Copy the code

To annotate the class with TestAnnotation, create a class Test and add @testannotation to the class definition

However, for annotations to work properly, a new concept needs to be introduced: meta-annotations

Yuan notes

A meta-comment is a comment that can be added to a comment, or a meta-comment is a basic comment that can be applied to other comments

Meta labels include @Retention, @documented, @target, @Inherited, and @REPEATable

@Retention

Retention Retention means Retention period. When @Retention is applied to a annotation, it explains the annotation’s lifetime

Its values are as follows:

  • The retentionPolicy.source annotation is only retained at the SOURCE stage and is discarded and ignored when the compiler compiles
  • The retentionPolicy.class annotation is only retained until compilation and is not loaded into the JVM
  • Retentionpolicy.runtime annotations can be retained until the application is run, and they are loaded into the JVM, so they can be retrieved while the application is running

@Retention is the equivalent of stamping a label with a time stamp that specifies the period in which the label was posted

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

In the code above, we specified that the TestAnnotation notation can be accessed during the run cycle of the program, so its life cycle is very long

@Documented

As the name implies, this meta-annotation must be related to the document. It provides the ability to include elements from annotations into Javadoc

@Target

Target means Target, and @target specifies where the annotation should be used

By analogy, tags can be posted anywhere you want, but thanks to @target, they can only be posted to methods, classes, method parameters, and so on. At sign Target has the following values

  • Elementtype. ANNOTATION_TYPE Annotates an annotation
  • Elementtype. CONSTRUCTOR can be annotated to a CONSTRUCTOR
  • Elementtype. FIELD can be used to annotate attributes
  • Elementtype. LOCAL_VARIABLE can be used to annotate local variables
  • ElementType.METHOD can annotate methods
  • Elementtype. PACKAGE can annotate a PACKAGE
  • Elementtype. PARAMETER can be used to annotate parameters within a method
  • Elementtype. TYPE can annotate a TYPE, such as a class, interface, or enumeration

@Inherited

Inherited means Inherited, but it does not mean that the annotations themselves can be Inherited. It means that if a superclass is annotated by @Inherited annotations, then if its subclass is not applied by any annotations, it inherits the superclass’s annotations

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}


@Test
public class A {}


public class B extends A {}
Copy the code

The Test annotation is annotated by @inherited, and when class A is annotated by Test, class B inherits FROM A, and class B has the Test annotation

@Repeatable

Repeatable means Repeatable

What annotations are used more than once? Usually the value of an annotation can be multiple at the same time

Take, for example, a person who is a programmer, a product manager, and 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{}Copy the code

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

What are container annotations? It’s a place to store other notes. It is a note in itself

Let’s look again at the relevant container annotations in the code

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

As specified, it must have a value property in it. The property type is an array of annotations annotated by @REPEATable. Note that it is an array

If it’s hard to understand, you can understand it this way. Persons is a generic tag filled with Person tags of the same type but with different content. To label Persons as SuperMan is to label him as programmer, product manager and painter.

Person(role= “PM”), which assigns PM to the role attribute of the annotation

Attributes of annotations

Attributes of annotations are also called member variables. Annotations have only member variables and no methods. An annotation’s member variable is declared in the annotation definition as a method of invisible parameters, whose method name defines the name of the member variable, and whose return value defines the type of the member variable

  1. The following code defines the TestAnnotation annotation that has the ID and MSG attributes. When used, we should assign values to them
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
	
	int id(a);
	
	String msg(a);

}
Copy the code

This is done by enclosing the annotation in parentheses with the form value=””, separated from multiple attributes by a comma

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

Note that the type of an attribute defined in an annotation must be the eight basic data types plus classes, interfaces, annotations, and their arrays

  1. Attributes in annotations can have default values, which need to be specified with the default key value. Such as
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
	
	public int id(a) default- 1;
	
	public String msg(a) default "Hi";

}

@TestAnnotation()
public class Test {}
Copy the code

The default value of the ID attribute in TestAnnotation is -1 and the default value of the MSG attribute is Hi. There is no need to assign the notation in parentheses following the @testannotation notation. This step can be omitted

  1. If an annotation contains only one attribute named value, the attribute value can be filled in parentheses when the annotation is applied
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
	String value(a);
}
Copy the code

The Check annotation only has the value attribute. So you can apply it this way

@Check("hi")
int a;
Copy the code

This has the same effect as the following

@Check(value="hi")
int a;
Copy the code
  1. Note also that if an annotation has no attributes, the parentheses can be omitted when the annotation is applied
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Perform {

}

@Perform
public void testMethod(a){}
Copy the code

Java preconfigured annotations

We learned about custom annotations above, but the Java language itself already provides several ready-made annotations

@Deprecated

This element is used to mark obsolete elements, which you might encounter in your daily development. When the compiler encounters this annotation at compile time, it will issue a reminder warning that the developer is calling an outdated element such as an outdated method, an outdated class, or an outdated member variable

Defines a Hero class that has two methods say() and speak(), where say() is annotated by @deprecated

public class Hero {
    @Deprecated
    public void say(a){
        Log.d("Hero"."I have nothing to say");
    }

    public void speak(a){
        Log.d("Hero"."I have a dream"); }}Copy the code

We then call them separately from the IDE



The say() method is underlined by a line, which the compiler recognizes as a reminder

@Override

This should be familiar, reminding subclasses to Override the @override method in their parent class

@SuppressWarnings

Prevent warning meaning. As mentioned earlier, the compiler will warn you when calling a method annotated by @deprecated, and sometimes developers will ignore this warning. They can do this by calling @SuppressWarnings from where they were called

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

@SafeVarargs

Parameter safety type annotations. Its purpose is to warn developers not to do anything unsafe with arguments, and its existence prevents compilers from generating such warnings

@FunctionalInterface

Functional interface annotations. A Functional Interface is a normal Interface that has a 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(a);
}
Copy the code

The Runnable we use in threaded development is a typical FunctionalInterface annotated by @functionalinterface

One might wonder why functional interface tags are useful, because functional interfaces can be easily converted to Lambda expressions. This is another topic, if you are interested, please search for related knowledge points to learn

Annotations and reflections

Annotations are obtained by reflection. You can first determine whether an annotation is applied to a Class object using the isAnnotationPresent() method

Annotations on a class

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

The Annotation object is then obtained using the getAnnotation() method

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
Copy the code

Or getAnnotations()

public Annotation[] getAnnotations() {}
Copy the code

The former method returns the Annotation of the specified type, and the latter method returns all annotations annotated to the element. If you get an Annotation that is not null, then you can call their property methods. Such as

Let’s open Up Eclipse and create a new one

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

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

}
Copy the code
@TestAnnotation()
public class HelloWorld {
	public static void main(String[] args) {
		boolean hasAnnotation = HelloWorld.class.isAnnotationPresent(TestAnnotation.class);
		if(hasAnnotation) {
			TestAnnotation testAnnotation = HelloWorld.class.getAnnotation(TestAnnotation.class);
			System.out.println("id:"+testAnnotation.id());
			System.out.println("msg:"+testAnnotation.msg());
		}else {
			System.out.println("nothing"); }}}Copy the code

The result of the program is



This is the default value for ID and MSG in TestAnnotation

Annotations on properties and methods

In the example above, we just check out the annotations on the class, but the annotations on the properties and methods are still ok

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

@TestAnnotation(msg="Hello")
public class HelloWorld {
	@Check(value="hi")
	int a;
	
	
	@Perform
	public void testMethod(a){}
	
	
	@SuppressWarnings("deprecation")
	public void test1(a){
		Hero hero = new Hero();
		hero.say();
		hero.speak();
	}


	public static void main(String[] args) {
		
		boolean hasAnnotation = HelloWorld.class.isAnnotationPresent(TestAnnotation.class);
		
		if ( hasAnnotation ) {
			TestAnnotation testAnnotation = HelloWorld.class.getAnnotation(TestAnnotation.class);
			// Get class annotations
			System.out.println("id:"+testAnnotation.id());
			System.out.println("msg:"+testAnnotation.msg());
		}
		
		
		try {
			// Get the attribute member of the class itself
			Field a = HelloWorld.class.getDeclaredField("a");
			// Sets the accessible flag of this object to the indicated Boolean value. A value of true indicates that the reflected object should be used without Java language access checks. A value of false indicates that the reflected object should perform Java language access checking.
			a.setAccessible(true);
			// Get an annotation on a member variable
			Check check = a.getAnnotation(Check.class);
			
			if( check ! =null ) {
				System.out.println("check value:"+check.value());
			} else {
				System.out.println("check is null");
			}
			
			Method testMethod = HelloWorld.class.getDeclaredMethod("testMethod");
			
			if( testMethod ! =null ) {
				// Get the annotation in the method
				Annotation[] ans = testMethod.getAnnotations();
				for( int i = 0; i < ans.length; i++) { System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName()); }}else {
				System.out.println("testMethod is null"); }}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 blocke.printStackTrace(); System.out.println(e.getMessage()); }}}Copy the code

Viewing the Running result



Note that @Retention(retentionPolicy.runtime) is required if an annotation is to be successfully extracted at RUNTIME

Usage scenarios for annotations

What are annotations really for? Let’s take a look at the official Java documentation

Annotations are a set of metadata that provides data to interpret program code, but annotations are not part of the interpreted code itself. Annotations have no direct effect on how the code works

Annotations are used as follows:

  • Provide information to the compiler: The compiler can use annotations to detect errors and warnings
  • Compile-time processing: Software tools can be used to generate code, Html documents, or other processing using annotation information.
  • Runtime processing: Some annotations can accept code extraction while the program is running

It is important to note that annotations are not part of the code itself

Annotations also do not change the code itself. Annotations are just tools of some tools, mainly for the compiler and other SoftWare tools.

When the developer modiifies the class, method, Field and other members with annotations, these annotations will not take effect by themselves. The developer must provide the corresponding code to extract and process Annotation information. The code that handles extracting and Processing annotations is called APT (Annotation Processing Tool)

chestnuts

To write A testing framework, test programmers for obvious exceptions in their code — Programmer A: I wrote A class called NoBug, because all its methods are error-free — me: Confidence is A good thing, but just in case of accidents, how about I test it? — Programmer A: How do you test it? — Me: Just add @jiecha to all the methods you write — Programmer A: Ok

NoBug.class

public class NoBug {
	@CheckError
	public void suanShu(a) {
		System.out.println("1234567890");
	}

	@CheckError
	public void jiafa(a) {
		System.out.println("1 + 1 =" + 1 + 1);
	}

	@CheckError
	public void jianfa(a) {
		System.out.println("1-1 =" + (1 - 1));
	}

	@CheckError
	public void chengfa(a) {
		System.out.println("3 x 5=" + 3 * 5);
	}

	@CheckError
	public void chufa(a) {
		System.out.println("6/0 =" + 6 / 0); }}Copy the code

This code above, some of these methods have the @checkerror annotation on them

@Retention(RetentionPolicy.RUNTIME)
public @interface CheckError {

}
Copy the code

Now you can test the corresponding method for NoBug

public class HelloWorld {
	public static void main(String[] args) {
		NoBug testobj = new NoBug();

		Class clazz = testobj.getClass();

		Method[] method = clazz.getDeclaredMethods();
		// 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 methods marked by @checkerror are tested
			if (m.isAnnotationPresent(CheckError.class)) {
				try {
					m.setAccessible(true);
					// The target method used to execute an object
					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 specific information about exceptions that occur 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 a test reportSystem.out.println(log.toString()); }}Copy the code

Viewing the Running result



The chufa() method in the NoBug class has an exception called ArithmeticException because it divides 0

Thus, with annotations I accomplish my own purpose, which is to test someone else’s code

So, when are annotations used? All I can tell you is, it depends what you want to do with it

Annotation Application Example

There are so many ways to use annotations, and Android development has come into contact with the following:

JUnit

JUnit is a testing framework, typically used as follows:

public class MyMathTest {

    @Test
    public void add(a) {... }}Copy the code

@test marks the method to Test add()

Previous JUnit article portal

ButterKnife

Classic usage

@BindView(R.id.tv_test)
TextView mTv;
Copy the code

Previous article on ButterKnife portal

, etc.

Frank909 wrote in detail and learned a lot (•̀ ω •́)y