前言
注解在初期开发中同样是一个少见却实用的功能,但无论是继续深入还是为现有代码提供助力,都需要对注解有一个清晰的认知
一、注解是什么?
注解,也叫元数据,是一种代码级别的说明。它是JDK1.5引入的一个特性,与类、接口、枚举类所在同一个层次。它可以声明在包、类、方法、成员变量、构造器、局部变量、方法参数等的上面,用来对这些元素进行说明、注释。也可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息
二、注解的使用
注解的分类
注解通常分为三大类:
- JDK自带注解
- 元注解
- 自定义注解
JDK自带注解
@Override: 表示注解修饰的方法必须满足重写的规则
@Deprecated: 表示成员过时,编译器可以在程序运行的时候获取到该注解
@SupressWarnings: 表示忽略编译器的警告
@FunctionalInterface: 表示该接口是一个函数式接口,并且可以作为Lambda表达式参数传入
@SafeVarargs:表示如果认为该方法或者构造方法是类型安全的,使用@SafeVarargs 跳过@SuppressWarnings(“unchecked”)检查
部分应用场景
Lists.newArrayList的源码
@SafeVarargs
@GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayList(E... elements) {
checkNotNull(elements); // for GWT
// Avoid integer overflow when a large array is passed in
int capacity = computeArrayListCapacity(elements.length);
ArrayList<E> list = new ArrayList<>(capacity);
Collections.addAll(list, elements);
return list;
}
如果缺少SafeVarargs注释,则将会丢失泛型信息
元注解
@Retention: 表示对它所标记的元素的生命周期(参考的范围看RetentionPolicy枚举类)
(1) RetentionPolicy.SOURCE :在源文件中有效(即源文件保留),编译时编> 译器会直接丢弃这种策略的注解;
(2) RetentionPolicy.CLASS : 在class文件中有效(即class保留),当运行> Java程序时, JVM不会保留注解。这是默认值
(3) RetentionPolicy.RUNTIME : 在运行时有效(即运行时保留),当运行 Java 程序时, JVM会保留注解。程序可以通过反射获取该注释。
@Target:表示标记定义的注解可以和什么目标元素绑定
(1) ElementType.TYPE :可以作用在类、接口和枚举类上;
(2) ElementType.METHOD :可以作用在方法上;
(3) ElementType.FIELD :可以作用在成员变量上;
(4) ElementType.CONSTRUCTOR :可以作用在构造器上;
(5) ElementType.LOCAL_VARIABLE :可以作用在局部变量上。
@Documented:表示该注解修饰的注解,可以被抽取到API文档中。
注意:定义为Documented的注解必须设置Retention值为RetentionPolicy.RUNTIME
@Inherited: 表示该注解可以被继承
自定义注解
声明自定义注解的元素
- 修饰符
访问修饰符必须为public,不写默认为pubic; - 关键字
关键字为@interface; - 注解名称
注解名称为自定义注解的名称,使用时还会用到; - 注解类型元素
注解类型元素是注解中内容,可以理解成自定义接口的实现部分;
自定义注解实例
返回指定的注解:getAnnotation
判断当前元素是否被指定注解修饰: isAnnotationPresent
返回所有的注解: getAnnotations
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Info {
String value() default "tracy";
boolean isDelete();
}
@Data
@Builder
// 为Person类配置了刚刚定义的注解@Info
@Info(isDelete = true)
public class Person {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 是否有效
*/
private boolean isDelete;
}
public class AnnotationTest {
public static void main(String[] args) {
try {
//获取Person的Class对象
Person person = Person.builder().build();
Class clazz = person.getClass();
//判断person对象上是否有Info注解
if (clazz.isAnnotationPresent(Info.class)) {
System.out.println("Person类上配置了Info注解!");
//获取该对象上Info类型的注解
Info infoAnno = (Info) clazz.getAnnotation(Info.class);
System.out.println("person.name :" + infoAnno.value() + ",person.isDelete:" + infoAnno.isDelete());
} else {
System.out.println("Person类上没有配置Info注解!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
方法参数上的注解
但要读取方法参数的Annotation就比较麻烦一点,因为方法参数本身可以看成一个数组,而每个参数又可以定义多个注解,所以,一次获取方法参数的所有注解就必须用一个二维数组来表示。例如,对于以下方法定义的注解:
public void hello(@NotNull @Range(max=5) String name, @NotNull String prefix) {
}
要读取方法参数的注解,我们先用反射获取Method实例,然后读取方法参数的所有注解:
// 获取Method实例:
Method m = ...
// 获取所有参数的Annotation:
Annotation[][] annos = m.getParameterAnnotations();
// 第一个参数(索引为0)的所有Annotation:
Annotation[] annosOfName = annos[0];
for (Annotation anno : annosOfName) {
if (anno instanceof Range) { // @Range注解
Range r = (Range) anno;
}
if (anno instanceof NotNull) { // @NotNull注解
NotNull n = (NotNull) anno;
}
}
原文链接:https://blog.csdn.net/qq_41788977/article/details/109191780
注解的语法
注解的基本语法:
- 注解是由@interface 关键字来描述的
- 注解是有成员的,这个成员类似成员变量,写法类似成员方法,没有参数没有声明异常
- 注解可以是 primitive type,String,Class,annotation,enumeration,一维数组
- 注解成员可以有默认值 int age() default 18;
- 注解规范之一:如果一个注解中只有一个成员,那么这个成员属性的名称叫做value;
- 如果一个注解没有任何成员,那么把该注解称为标记注解
注解大全
详细见大佬文章:https://blog.csdn.net/qq_42618394/article/details/118003088