Knowledge points combing: Java notes

Java annotations

Foreword

Recently, I have been sorting out some of the knowledge I have learned, intending to record them well, perfecting my personal knowledge system, and stick to it! Rushing


why learn

Spring, Mybatis, lombok, etc. We have touched a lot of frameworks when developing programs. Most of them provide their own implementation notes. Skilled use can help me complete my program, but how did he do it? How does a small annotation achieve such a powerful function, I decided to study the Java annotation mechanism carefully by thinking about this problem

What is Annotation

Annotations were introduced by JDK5 and are Java's support for metadata. In human language, it is a special mark in the code. These marks can be read and executed at some time, so developers can enhance our program without changing the logic of the original business code.


First look at a few basic annotations provided by Java

  • @Override
  • @Deprecated
  • @SupressWarning

The above annotations often appear in various source codes. To be honest, before annotating knowledge on the side of the system, I always look at the annotations. What do I write, I do n’t understand? ? ? ?

After reading some books and sorting them out, it suddenly becomes bright

Let me listen slowly

@Override

⚠️ Note: This annotation can only be used in methods (why do you say below)

This annotation is very common. Every time you rewrite the parent method or implement the interface method, the intelligent development tool will automatically add such an annotation to me. At first, I rejected it. Later I learned that this annotation is added To help developers check whether the implementation of the parent class method is correct.

For a chestnut, if there is a method called hello in the parent class, then the subclass inheriting it can be rewritten to him, in case he missed it and wrote it as helo. Can be seen as a new method of the subclass, at this time the program can be executed correctly. But if the @Override annotation is added to the helo method, then the compiler knows that this method is a subclass to rewrite the parent class method, it will automatically check whether the parent class method is rewritten correctly (obviously the parent The class has no helo method, we need to rewrite hello (), then it will compile error)

A bunch of words, one sentence is that @Override is to help developers check whether the rewritten method is correct (check the return value of the method name parameter, etc.)

@Deprecated

⚠️ Note: This annotation can be used on classes and methods

The meaning of this comment is very simple, it is used to mark outdated code

public class TestAnnotation {

	public static void main(String[] args) {
		new DeprecatedClass().info();
	}
	
}

// 下面定义了一个类,加了@Deprecated表示他是过时的
// 类中有一个方法,也是过时的 23333


@Deprecated
class DeprecatedClass {
	
	@Deprecated
	public void info() {
		System.out.println("giao");
	}
	
}
复制代码

If you compile this program, you will be warned that this class and this method are outdated, but does not affect program execution

@SuppressWarnings

This annotation can help eliminate warnings at compile time

As a chestnut, there is a method sayHello () in my program. This method returns a String. When I call this method, I just call but ignore the return value of using this method. Then when I compile this program, just There will be a warning that I ignore the return value. At this time, I can add @SuppressWarnings ("unused") to the method. Unused means unused warning. This usage will tell the compiler to ignore this warning. This warning will no longer be issued

public class TestAnnotation {

	public static void main(String[] args) {
		// 如果我不加这个注解就会有警告,but你可以不理他,警告并不会对程序运行有影响
		@SuppressWarnings("unused")
		String string = new SuppressWarningClass().sayHello();
	}

}

class SuppressWarningClass {
	
	public String sayHello() {
		return "hello";
	}
	
}
复制代码

The above three annotations are a few basic annotations provided by Java (of course, more than that). The examples are just to help us quickly understand the annotations. Try out the annotations quickly. Let ’s read them in depth to understand them. The secret behind


Meta Annotation provided by Java

The definition of an annotation must be the meta annotation. Java comes with several meta annotations to help modify the definition of other annotations.

@Retention

This annotation can only be modified to other annotations. It is used to specify the retention time of the modified annotation. @Retention annotation contains a member variable value of type RetentionPolicy. We set the retention time by specifying the value of the value (the specified method is actually It is @Retention (value = RetentionPolicy.RUNTIME), which is specified by passing the corresponding member variable name = value in parentheses)

For the retention time of annotations, the value of @Retention can only be set by three

  1. RetentionPolicy.SOURCE: The modified Annotation can only be in the source code and will be ignored by the compiler directly
  2. RetentionPolicy.CLASS: The modified Annotation can be stored in the compiled class file, but cannot be obtained at runtime
  3. RetentionPolicy.RUNTIME: The modified Annotation can exist in the class file, and the Annotation information can be obtained by reflection during operation
@Retention(RUNTIME) // 设置其可存活的时间
public @interface MyAnnotation {

}
复制代码

by the way, if you only need to assign a value to a member variable named value in the annotation, you can specify it without name = value and just write it. In the chestnut above, @Retention (RUNTIME) uses this method to directly assign values ​​to values

@Target

This annotation is also used to modify the annotation annotation. It is used to specify that the modified annotation can only be used in the program unit. For example, the @Override annotation introduced above is because the @Target specification can only be modified on the method.

@Target has many values, it has an enumeration of ElementType:

  1. Class or interface: ElementType.TYPE;
  2. Field: ElementType.FIELD;
  3. Method: ElementType.METHOD;
  4. Construction method: ElementType.CONSTRUCTOR;
  5. Method parameters: ElementType.PARAMETER
  6. Can only be used to modify annotations: ElementType.ANNOTATION_TYPE
  7. Local variable: ElementType.LOCAL_VARIABLE
  8. Package definition: ElementType.PACKAGE

@ Target's source code is like this

@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();
}
复制代码

It is defined as an annotation that can only be modified, it has a member variable value, so we can directly define the value in parentheses, as I said above, there is no need to add value =, you can notice that the value type here ElementType [], this is an array, then it means that if we need to define multiple, we can specify it directly in the form of an array, like the following

@Target({CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
复制代码

@Document

This annotation has less effect than the above two, and its name can be seen to be related to the document

Annotations modified by this annotation can be viewed in the documentation generated by javadoc, nothing more ...

@Inherited

Annotations modified by this annotation will have inheritance. For example, there is an annotation X modified by @Inherited. If the X annotation is added to class A, then its subclasses will automatically add X annotations (quietly add You can see it by looking at the compiled code ~)


Custom annotation

There are a lot of bedding on it, let ’s try to define annotations by ourselves

Definition Annotation

Defining an annotation is similar to defining an interface. The keyword of the interface is interfac, and the keyword of the annotation is @interface (that is, add an @ on the basis of the interface)

public @interface MyAnnotation {

}
复制代码

Using this annotation is also very simple, just add it directly to the head you want to use

@MyAnnotation
class TestMyAnnotation {
	
	@MyAnnotation
	public void testMethod() {
		
	}
	
}
复制代码

Annotations can have their own member variables

public @interface MyAnnotation {

	String value();
	
	int age();
	
}
复制代码

After defining member variables, they must be assigned values ​​when used

@MyAnnotation(value = "test", age = 123)
class TestMyAnnotation {
	
	@MyAnnotation(value = "abc", age = 234)
	public void testMethod() {
		
	}
	
}
复制代码

Of course, you can also set a default value for them, so that you do n’t need to assign a value when you use it. When you do n’t assign a value, the default value is used directly.

Use the devalut keyword to set the default value for its implementation

public @interface MyAnnotation {

	String value() default "abc";
	
	int age() default 123;
	
}
复制代码

Depending on whether you have member variables, Annotation can be divided into the following two types:

  1. Mark Annotation: Annotation of no member variables, they only use their own existence to provide information, such as @Override, etc. introduced earlier
  2. Meta Annotation: There are member variables, they can accept more data, so it is also called Meta Annotation

Extract Annotation information

Having said so many Annotations, I also introduced how to customize an Annotation. The question is, how exactly do these Annotations work? We continue to explore

Extract data

An Annotation has no effect only by virtue of its own. Developers must provide corresponding tools to extract their information to make it work.

We define an annotation. In fact, it essentially implements the annotation interface provided by Java. The annotation interface is the parent interface of all annotations. At the same time, Java5 introduces the AnnotatedElement interface. This interface is the parent interface of all program elements (such as class, interface, method, etc.), so through reflection, and using the method provided by AnnotatedElement to us, we can get the information in the annotations. , Directly on the code

AnnotatedElement provides several very useful methods to help us get the information of annotations

  1. getAnnotation (Class) where Class is the specific type passed in, such as MyAnnotation.class, get annotations according to the type, or return Null if it cannot be obtained
  2. getDeclaredAnnotation (Class) This method is the same as getAnnotation above. The only difference is that it gets the annotations directly modified on the method. Remember if the annotations we mentioned above are inherited (by using @Inherited), using this method is not Will get inherited annotations
  3. getAnnotations (): This means getting all annotations on the object
  4. getDeclaredAnnotations (): also used to get all annotations, the difference is the same as getAnnotation and getDeclaredAnnotation
  5. isAnnotationPresent (Class): Here Class is the specific type passed in, such as MyAnnotation.class, used to determine whether there are annotations of this type on the object element, if it is true, it returns true, otherwise it returns false
  6. getAnnotationsByType (): returns the annotation array of the specified type existing on the program element (due to the new annotation feature added in Java 8, the difference between this method and the above getAnnotations is that one gets all according to the type, one gets all)
  7. getDeclaredAnnotationsByType (): The meaning is similar to the above getAnnotationsByType, the difference is that the annotations that directly act on the elements are obtained (the difference is the same as getAnnotation and getDeclaredAnnotation)
public void getMyAnnotation() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
	Annotation[]  annotations = Class.forName("com.learn.javase.TestMyAnnotation").getMethod("testMethod").getAnnotations();
	for (Annotation annotation : annotations) {
		System.out.println(annotation);
	}
}
复制代码

The above code is the easiest way to get Annotation on the method. Here we use the getAnnotations method provided by AnnotatedElement to get all the annotations on this program element and print it out in a loop.

Further, if you want to get the value of the member variable in the annotation is also very simple

public void getMyAnnotation2() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
	Method[] methods = Class.forName("com.learn.javase.TestMyAnnotation").getMethods();
	for (Method method : methods) {
		MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
		// 此处需要做一个判空
		if (myAnnotation != null) {
			System.out.println("value="+myAnnotation.value()+",age="+myAnnotation.age());
		}
	}
}
复制代码

Java8 repeated annotations

In fact, there are repeated annotations before Java8, but only through a curve. First of all, Java does not allow two identical comments on a program element, such as the following, the program compilation will directly report an error

@MyAnnotation(value = "test", age = 123)
@MyAnnotation(value = "test", age = 234)
class TestMyAnnotation3 {
	
}
复制代码

But this operation can be achieved in a special way, which is to define an annotation container, such as:

@Retention(RUNTIME) // 设置其可存活的时间
public @interface MyAnnotationColloection {

	MyAnnotation[] value();
		
}
复制代码

Through this definition, you can achieve repeated annotations in a strange gesture, like this:

@MyAnnotationColloection({@MyAnnotation(value = "test", age = 123),@MyAnnotation(value = "test", age = 123)})
class TestMyAnnotation3 {
	
}
复制代码

Pay attention to this place, the storage time of the container must be greater than or equal to the specific annotation

However, this is really not very beautiful, so Java8 introduced @Repeatable annotation, we can add @Repeatable annotation to modify when defining @MyAnnotation, value is passed into the container class, like this:

@Repeatable(MyAnnotationColloection.class)
@Retention(RUNTIME) // 设置其可存活的时间
public @interface MyAnnotation {

	String value() default "abc";
	
	int age() default 123;
	
}
复制代码

So now we can use repeat annotations more beautifully

@MyAnnotation(value = "test", age = 123)
@MyAnnotation(value = "test", age = 123)
//@MyAnnotationColloection({@MyAnnotation(value = "test", age = 123),@MyAnnotation(value = "test", age = 123)})
class TestMyAnnotation3 {
	
}
复制代码

But to put it bluntly in this way, the essence is still the same as the one originally introduced. The new way of writing is just a simplification of the old method, because it is still repeatedly defined in the form of a container


New Type Annotation in Java 8

In Java8, ElementType adds two enumeration members, TYPE_PARAMETER and TYPE_USE. Annotations can only be marked on one declaration (such as fields, classes, methods) before Java8. After Java8, the newly added TYPE_PARAMETER can be used to mark type parameters. TYPE_USE can be used to label any type (not including class).

If defined as this range, the annotation can be modified in the following positions:

  1. When creating an object (before a new object)
  2. When type conversion
  3. When implementing the interface
  4. throws when an exception is thrown
class D<@Parameter T> { }class Image implements @Rectangular Shape { }new @Path String("/usr/bin")
 
 
String path=(@Path String)input;if(input instanceof @Path String)public Person read() throws @Localized IOException.List<@ReadOnly ? extends Person>List<? extends @ReadOnly Person>
 
@NotNull String.class 

import java.lang.@NotNull String
复制代码

APT

I will only give a brief introduction about this concept here, because personal contact is very limited.

APT (Annotation Processing Tool) is an annotation processing tool that is used to generate code. In other words, this is a tool for generating code using code. The purpose of using it is to simplify the workload of developers. The definition of Annotation processor needs to inherit an AbstractProcessor parent class. Through the methods provided by it, we can obtain the information of this Annotation and perform the operation you want by means other than reflection.

After implementing a specific APT, its operation depends on special javac commands

javac -processor APT的类名 具体的java文件.java
复制代码

Guess you like

Origin juejin.im/post/5e9c492fe51d45471263fa18