先把 4 个东西一句话讲清
- @Target → 规定注解能贴在哪(类 / 方法 / 变量)
- @Retention → 规定注解运行时还活着(必须写)
- isAnnotationPresent → 检查有没有贴这个注解(返回 true/false)
- getAnnotation → 拿到注解本身,读取里面的值
一、前言:到底什么是注解?
一句话总结:注解就是贴在类、方法、变量上的「特殊标签」。
- 单纯贴上标签:毫无作用
- 通过反射扫描读取标签:注解才会产生对应的功能
我们日常使用的 @Override、@SuppressWarnings、Spring的@Controller,本质全部都是注解。
二、四大核心知识点(必学)
自定义注解离不开4个核心部分,我帮你用最简单的语言拆分:
1. @Target(元注解)------ 管控注解【贴在哪里】
作用:给自定义注解制定规则,限制这个标签能粘贴的位置,禁止乱贴。
常用取值(小白只需要背这5个):
ElementType.TYPE:可以贴在类、接口、枚举上ElementType.FIELD:可以贴在成员变量上ElementType.METHOD:可以贴在成员方法上ElementType.CONSTRUCTOR:可以贴在构造方法上ElementType.PARAMETER:可以贴在方法参数上
补充:不添加@Target,注解默认可以贴在任意位置。
2. @Retention(元注解)------ 管控注解【活多久】
作用 :控制注解的生命周期,自定义注解想要被反射读取,必须配置它。
三种生命周期:
SOURCE:源码阶段有效,编译后直接丢失(如@Override)CLASS:编译阶段有效,运行阶段丢失(默认值)RUNTIME:运行阶段一直存在,唯一能被反射读取(自定义注解必选)
💡 小白铁律:只要是需要自己写、需要读取的自定义注解,无脑写
@Retention(RetentionPolicy.RUNTIME)
3. isAnnotationPresent() ------ 判断【有没有贴标签】
作用:通过反射,判断某个类/方法/变量上是否标注了指定注解。
返回值:布尔类型
true:已添加该注解false:未添加该注解
4. getAnnotation() ------ 读取【标签内部数据】
作用:如果已经判断存在注解,通过该方法获取注解对象,进而读取注解内部存储的参数值。
三、完整实战案例(全程可直接运行)
步骤1:自定义注解
定义注解,限制仅能贴在类上,设置运行时永久存活,并自定义两个属性存储数据。
java
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 MyAnno {
// 自定义注解参数
String name();
int age();
}
步骤2:使用注解
在实体类上添加注解,并给注解内部参数赋值。
kotlin
// 给User类打上标签,并传入数据
@MyAnno(name = "掘金小白", age = 18)
public class User {
private String username;
private String password;
}
步骤3:反射读取注解(核心)
先判断是否存在注解,再获取注解对象、读取内部数据。
arduino
public class AnnotationTest {
public static void main(String[] args) {
// 1. 获取类的Class对象
Class<User> clazz = User.class;
// 2. 判断类上是否存在@MyAnno注解
boolean isExist = clazz.isAnnotationPresent(MyAnno.class);
System.out.println("是否添加注解:" + (isExist ? "是" : "否"));
// 3. 存在注解则读取内部数据
if(isExist){
// 获取注解对象
MyAnno anno = clazz.getAnnotation(MyAnno.class);
// 读取注解参数
String name = anno.name();
int age = anno.age();
System.out.println("注解存储姓名:" + name);
System.out.println("注解存储年龄:" + age);
}
}
}
步骤4:运行结果
是否添加注解:是
注解存储姓名:掘金小白
注解存储年龄:18
四、拓展:注解贴在方法上(补充案例)
修改注解@Target,支持粘贴在方法上,实现方法级别的注解读取。
less
// 可贴在类 和 方法上
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
String name();
int age();
}
使用+读取:
csharp
public class User {
@MyAnno(name = "测试方法", age = 20)
public void login(){
System.out.println("用户登录");
}
}
ini
import java.lang.reflect.Method;
public class AnnotationTest {
public static void main(String[] args) throws Exception {
Class<User> clazz = User.class;
// 获取指定方法
Method loginMethod = clazz.getMethod("login");
if(loginMethod.isAnnotationPresent(MyAnno.class)){
MyAnno anno = loginMethod.getAnnotation(MyAnno.class);
System.out.println(anno.name());
}
}
}
五、终极总结(背诵版)
- @Target:约束注解的使用位置,防止注解乱贴
- @Retention :设置注解生命周期,自定义注解必须配置
RUNTIME才能被反射读取 - isAnnotationPresent() :做判断,查询目标位置是否存在指定注解
- getAnnotation() :获取注解对象,读取注解内部存储的参数
六、极简口诀
Target定位置,Retention保性命; 先判是否存在,再拿注解取值!