# 注解学习

JDK1.5 开始引入注解(Annotation),Java 中类、方法、变量、参数都可以被标注。

注解主要作用:

  • 生成文档,通过代码中标识的注解生成 javadoc 文档。
  • 编译检查,通过代码中标识的注解让编译器在编译期间进行检查。
  • 编译时动态处理,编译时通过代码里标识的注解动态处理,例如动态生成代码。
  • 运行时动态处理,运行时通过代码里标识的注解动态处理,例如使用反射注入实例。

关于三个名词:元注解(meta-annotation)、元数据(meta-data)、注解(annotation),我个人认为元注解是注解注解的注解,元数据是注解别称。

# JDK 内置的注解

# @Override

java.lang 包下,表示当前的方法定义将覆盖父类中的方法。

  • 作用于方法
  • 源码保留级别

1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

# @Deprecated

java.lang 包下,表示代码被弃用,如果使用了被 @Deprecated 注解的代码则编译器将发出警告。

  • 生成文档
  • 运行时保留级别
  • 作用于构造器、属性、局部变量、方法、包、参数、类型

1
2
3
4
5
6
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {

}

# @Suppvisewarnings

java.lang 包下,告诉编译器忽略指定的 警告信息。

  • 可修饰包括类型、属性、方法、参数、构造器、局部变量
  • 源码保留级别

1
2
3
4
5
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* 抑制单类型的警告:
*/
@SuppressWarnings("unchecked")
public void addItems(String item) {
@SuppressWarnings("rawtypes")
List items = new ArrayList();
……
}

/*
* 抑制多类型的警告:
*/
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public void addItems(String item) {
……
}

具体警告类型查表:

参数作用原描述
all抑制所有警告to suppress all warnings
boxing抑制装箱、拆箱操作时候的警告to suppress warnings relative to boxing/unboxing operations
cast抑制映射相关的警告to suppress warnings relative to cast operations
dep-ann抑制启用注释的警告to suppress warnings relative to deprecated annotation
deprecation抑制过期方法警告to suppress warnings relative to deprecation
fallthrough抑制确在 switch 中缺失 breaks 的警告to suppress warnings relative to missing breaks in switch statements
finally抑制 finally 模块没有返回的警告to suppress warnings relative to finally block that don’t return
hiding抑制与隐藏变数的区域变数相关的警告to suppress warnings relative to locals that hide variable()
incomplete-switch忽略没有完整的 switch 语句to suppress warnings relative to missing entries in a switch statement (enum case)
nls忽略非 nls 格式的字符to suppress warnings relative to non-nls string literals
null忽略对 null 的操作to suppress warnings relative to null analysis
rawtype使用 generics 时忽略没有指定相应的类型to suppress warnings relative to un-specific types when using
restriction抑制与使用不建议或禁止参照相关的警告to suppress warnings relative to usage of discouraged or
serial忽略在 serializable 类中没有声明 serialVersionUID 变量to suppress warnings relative to missing serialVersionUID field for a serializable class
static-access抑制不正确的静态访问方式警告to suppress warnings relative to incorrect static access
synthetic-access抑制子类没有按最优方法访问内部类的警告to suppress warnings relative to unoptimized access from inner classes
unchecked抑制没有进行类型检查操作的警告to suppress warnings relative to unchecked operations
unqualified-field-access抑制没有权限访问的域的警告to suppress warnings relative to field access unqualified
unused抑制没被使用过的代码的警告to suppress warnings relative to unused code

# 元注解

元注解就是注解注解的注解,一般用于修饰注解

	除了JDK定义好的注解,我们还可以自定义注解,JDK1.5提供了四个标准用来对注解类型进行注解的注解类
  • @Target

  • @Retention

  • @Document

  • @Inherited

# @Target 注解

描述注解的使用范围

Target 注解用来说明被注解的注解类可修饰的对象的范围:

	注解可以修饰packages types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量

取值范围在 ElementType 枚举中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public enum ElementType {

TYPE, // 类、接口、枚举类

FIELD, // 成员变量(包括:枚举常量)

METHOD, // 成员方法

PARAMETER, // 方法参数

CONSTRUCTOR, // 构造方法

LOCAL_VARIABLE, // 局部变量

ANNOTATION_TYPE, // 注解类

PACKAGE, // 可用于修饰:包

TYPE_PARAMETER, // 类型参数,JDK 1.8 新增

TYPE_USE // 使用类型的任何地方,JDK 1.8 新增

}

# @Retention 注解

描述注解保留的时间范围

	限定所注解的注解类注解到其他类上后,可以被保留到何时,一共三个策略,定义在RetentionPolicy枚举中:

1
2
3
4
5
public enum RetentionPolicy {
SOURCE, // 源文件保留
CLASS, // 编译期保留,默认值
RUNTIME // 运行期保留,可通过反射去获取注解信息
}

# @Documented 注解

描述在使用 javadoc 工具为类生成帮助文档时是否需要保留注解信息

# @Inherited 注解

使被修饰的注解具有继承性

# 注解与反射

我们知道 spring 中有很多注解很实用,如使用注解驱动 ioc 依赖注入,好的注解可以简化代码提高效率。

# AnnotationElement

java.lang.reflect 包下有 AnnotationElement 接口,标识一个被注解的 Java 语言元素(Class、Method、Field、Constructor、GenericDeclaration 等对应的实现都实现了该接口),用于获取注解的内容。** 注意:只有注解作用范围定义为 RUNTIME 时,该注解才运行时可见,这样 class 文件被装载时其中的注解才能被虚拟机读取。 **

image-20230121095228782

方法使用:

  • isAnnotationPresent(Class<? extends Annotation>)

判断元素上是否包含指定类型的注解,包含则返回 true,反之 false

  • getAnnotation(Class<T>)

    返回该元素上的注解,不存在返回 null

  • getAnnotations()

    返回该元素存在的所有注解(数组形式),无注解返回长度 0 的数组

  • getAnnotationsByType(Class<T>)

    返回指定类型的注解数组

  • 另外加 Declared 的方法跟不加的差不多,只不过多了一个忽略继承的注解

# 自定义注解

注解 @Extra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.FIELD})
@Inherited
public @interface Extra {
enum Type {
/**
* 类
*/
CLASS,
/**
* 方法
*/
METHOD
}

//声明枚举
Type type() default Type.CLASS;
String value() default "默认";
}

使用注解的类 TestAnnotation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestAnnotation {

@Extra("覆盖默认A")
public void hasAnnoA(){
System.out.println("方法");
}

@Extra("覆盖默认B")
public void hasAnnoB(){
System.out.println("方法");
}

public void noAnno(){
System.out.println("方法");
}
}

主类 Main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
public static void main(String[] args) {
// 获取TestAnnotation所有方法
Method[] methods = TestAnnotation.class.getMethods();
//Lambda取methods中注解了@Extra的方法的注解值
Stream.of(methods).filter(method -> method.isAnnotationPresent(Extra.class))
.forEach(method -> System.out.println(method.getAnnotation(Extra.class).value()));
}

// 上面Lambda等同于下面foreach
for(Method method: methods){
if(method.isAnnotationPresent(Extra.class)){
System.out.println(method.getDeclaredAnnotation(Extra.class).value());
}
}
}

显示:

1
2
覆盖默认A
覆盖默认B

更新于 阅读次数 本文阅读量:

请我喝[茶]~( ̄▽ ̄)~*

Windlinxy 微信支付

微信支付

Windlinxy 支付宝

支付宝