5-3-java注解annotation

文章目录
  1. 1. java注解
    1. 1.1. 脑图
    2. 1.2. 四种标准元注解
      1. 1.2.1. @interface(声明Annotation,自定义annotation)
      2. 1.2.2. @Documented(javadoc)
      3. 1.2.3. @Target(指定Annotation的类型, 1~n个ElementType)
      4. 1.2.4. @Retention(指定Annotation的策略,1个RetentionPolicy)
    3. 1.3. java 常用的Annotation
      1. 1.3.1. @Inferited
      2. 1.3.2. @Deprecated
      3. 1.3.3. @SuppressWarnings
    4. 1.4. annotation作用
      1. 1.4.1. 编译检查
      2. 1.4.2. 反射中使用(aop去打log等非业务相关但必须做的,减少代码入侵)
      3. 1.4.3. 根据Annotation生成帮助文档
      4. 1.4.4. 能够帮忙查看查看代码

java注解

annotation是一个接口,可以通过反射来获取指定程序种元素的annotation对象,通过该annotation对象来获取注解中的元数据信息。

脑图

![image-20210722144151169](/gitee-internal-blog/images/5-3-java annotation.png)

四种标准元注解

https://www.cnblogs.com/skywang12345/p/3344137.html

1
2
3
4
5
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}

@interface(声明Annotation,自定义annotation)

使用@interface定义注解时,意味着它实现了java.lang.annotation.Annotation接口,即该注解就是一个Annotation。定义Annotation时,@interface是必须的。

@Documented(javadoc)

如果使用@Documented修饰该Annotation,则表示它可以出现在javadoc中。

@Target(指定Annotation的类型, 1~n个ElementType)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */

FIELD, /* 字段声明(包括枚举常量) */

METHOD, /* 方法声明 */

PARAMETER, /* 参数声明 */

CONSTRUCTOR, /* 构造方法声明 */

LOCAL_VARIABLE, /* 局部变量声明 */

ANNOTATION_TYPE, /* 注释类型声明 */

PACKAGE /* 包声明 */
}

@Retention(指定Annotation的策略,1个RetentionPolicy)

1
2
3
4
5
6
7
public enum RetentionPolicy {
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */

CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */

RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}

a) 若Annotation的类型为 SOURCE,则意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了。
例如,“ @Override ”标志就是一个Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,“@Override”就没有任何作用了。
b) 若Annotation的类型为 CLASS,则意味着:编译器将Annotation存储于类对应的.class文件中,它是Annotation的默认行为。
c) 若Annotation的类型为 RUNTIME,则意味着:编译器将Annotation存储于class文件中,并且可由JVM读入。

java 常用的Annotation

1
2
3
4
5
6
7
@Deprecated  -- @Deprecated 所标注内容,不再被建议使用。
@Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
@Documented -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
@Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
@Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。

@Inferited

假设,我们定义了某个Annotaion,它的名称是MyAnnotation,并且MyAnnotation被标注为@Inherited。现在,某个类Base使用了MyAnnotation,则Base具有了“具有了注解MyAnnotation”;现在,Sub继承了Base,由于MyAnnotation是@Inherited的(具有继承性),所以,Sub也“具有了注解MyAnnotation”。

@Deprecated

若某个方法被 @Deprecated 标注,则该方法不再被建议使用。如果有开发人员试图使用或重写被@Deprecated标示的方法,编译器会给相应的提示信息。

@SuppressWarnings

让编译器对“它所标注的内容”的某些警告保持静默。例如,”@SuppressWarnings(value={“deprecation”, “unchecked”})” 表示对“它所标注的内容”中的 “SuppressWarnings不再建议使用警告”和“未检查的转换时的警告”保持沉默。

![image-20210724150627490](/gitee-internal-blog/images/5-3-java annotation1.png)

annotation作用

编译检查

例如,@SuppressWarnings, @Deprecated和@Override都具有编译检查作用。
(01) 关于@SuppressWarnings和@Deprecated。

(02) 若某个方法被 @Override的 标注,则意味着该方法会覆盖父类中的同名方法。如果有方法被@Override标示,但父类中却没有“被@Override标注”的同名方法,则编译器会报错。

反射中使用(aop去打log等非业务相关但必须做的,减少代码入侵)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String[] value() default "unknown";
}

/**
* Person类。它会使用MyAnnotation注解。
*/
class Person {

/**
* empty()方法同时被 "@Deprecated" 和 “@MyAnnotation(value={"a","b"})”所标注
* (01) @Deprecated,意味着empty()方法,不再被建议使用
* (02) @MyAnnotation, 意味着empty() 方法对应的MyAnnotation的value值是默认值"unknown"
*/
@MyAnnotation
@Deprecated
public void empty(){
System.out.println("\nempty");
}

/**
* sombody() 被 @MyAnnotation(value={"girl","boy"}) 所标注,
* @MyAnnotation(value={"girl","boy"}), 意味着MyAnnotation的value值是{"girl","boy"}
*/
@MyAnnotation(value={"girl","boy"})
public void somebody(String name, int age){
System.out.println("\nsomebody: "+name+", "+age);
}
}

public class AnnotationTest {

public static void main(String[] args) throws Exception {

// 新建Person
Person person = new Person();
// 获取Person的Class实例
Class<Person> c = Person.class;
// 获取 somebody() 方法的Method实例
Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class});
// 执行该方法
mSomebody.invoke(person, new Object[]{"lily", 18});
iteratorAnnotations(mSomebody);


// 获取 somebody() 方法的Method实例
Method mEmpty = c.getMethod("empty", new Class[]{});
// 执行该方法
mEmpty.invoke(person, new Object[]{});
iteratorAnnotations(mEmpty);
}

public static void iteratorAnnotations(Method method) {

// 判断 somebody() 方法是否包含MyAnnotation注解
if(method.isAnnotationPresent(MyAnnotation.class)){
// 获取该方法的MyAnnotation注解实例
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
// 获取 myAnnotation的值,并打印出来
String[] values = myAnnotation.value();
for (String str:values)
System.out.printf(str+", ");
System.out.println();
}

// 获取方法上的所有注解,并打印出来
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation);
}
}
}

根据Annotation生成帮助文档

通过给Annotation注解加上@Documented标签,能使该Annotation标签出现在javadoc中。

能够帮忙查看查看代码

通过@Override, @Deprecated等,我们能很方便的了解程序的大致结构。
另外,我们也可以通过自定义Annotation来实现一些功能。