Annotation其实是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理
通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充信息
Annotation就像修饰符一样被使用,可用于修饰类、构造器、方法、成员变量、参数…,这些信息被存储在Annotation的“属性名=属性值”键值对中
注解定义
语法
权限修饰符 @interface 注解名字{
// 注解体定义
属性类型 属性名();
属性类型 属性名();
属性类型 属性名();
......
属性类型 属性名() default value;
}
举例:
public @interface Override {
}
属性类型:
基本数据类型
String类型
Class类型
注解类型
枚举类型
以及以上类型的数组形式
注意:注解不允许继承
注解和接口的关系:
注解和接口的定义都使用同一个关键字interface,而且注解体的定义也非常类似于接口中的抽象方法。因为注解本身就是一种特殊的接口。
也就是说:
- 当你使用”@interface”关键字定义一个注解类型时,它会自动实现java.lang.annotation.Annotation接口,即使你没有显式地声明这个继承关系。
- 如果使用”interface”关键字定义一个接口类型,并显式地让它继承java.lang.annotation.Annotation接口,那么这个新接口也不会被视为一个注解类型。
- java.lang.annotation.Annotation接口本身并不是一个注解类型,它只是一个普通的接口类型。
- 注解类型并不能显式地继承其他类或接口,虽然它确实隐式实现了接口java.lang.annotation.Annotation~
当然,以上概念了解即可。虽然注解和接口确实共享了同一个关键字,但它们在实际使用中具有不同的目的和功能,可谓千差万别
元注解
元注解:描述修饰注解的注解(注解的注解)

常用元注解:
@Retention元注解,来定义我们自己定义的注解的保留级别.
- RetentionPolicy.RUNTIME (运行时有效)
- RetentionPolicy.CLASS (字节码中有效) 默认
- RetentionPolicy.SOURCE (源代码中有效)
@Target元注解,注解可以作用的目标
对于注解而言,可以作用的目标:
- 整个类 ElementType.TYPE
- 成员变量 ElementType.FIELD
- 构造方法 ElementType.CONSTRUCTOR
- 成员方法 ElementType.METHOD
了解:
@Inherited元注解,如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
@Document元注解,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成文档时,会显示@B。
注解的使用
类比类对象
User user = new User("zs",20);
User user2 = new User();
使用的时候注解需要通过@符号进行实例化, 对每个属性都要赋值
@注解名(属性1=属性值,属性2=属性值)
解释:
- “@”可以认为相当于“new”关键字,必不可少。
- 注解相当于给Java代码打上一个标签,所以它必须要修饰Java代码的一个结构。比如修饰一整个类,一整个方法,一个成员变量等等。
- 实例化注解时,必须给注解的各个属性赋值,赋值方式是:属性名 = 属性值。如果是数组类型的注解属性,用”{}”赋值。如果有多个属性,赋值时用”,”隔开。
注意事项:
- 每个属性都要赋值
- 可以不赋值,但是要有默认值, default
- 数组形式赋值 {}
- 如果只有1个属性, 名字叫value, 可以简化赋值
- 如果属性类型是引用类型, 不能是null
示例
@MyAnnotation
public class Test {
@MyAnnotation(666)
int num;
@MyAnnotation(value = 777, b = "777", c = {"777","aaa","bb"})
public void test() {
}
}
@interface MyAnnotation {
int value() default 123;
String b() default "abc";
String[] c() default {"123"};
}
注解处理器
什么是注解处理器?
- 获取注解信息, 根据注解信息进行处理
如何获取注解信息?
- 通过反射获取注解信息
基本逻辑
- 获取注解所加的类的对应的Class对象
- 通过Class对象获取注解所加的类中的结构(Filed, Constructor, Method)对象
- 通过该结构对象判断是否使用了注解
- 通过该结构对象获取注解实例
- 通过注解实例获取注解属性信息
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception{
// 获取字节码文件对象
Class<?> c = Class.forName("_24annotation.com.cskaoyan._04handle.Demo");
// 拿到方法对象
Method loginMethod = c.getDeclaredMethod("login");
// 判断方法上是否使用了注解
boolean annotationPresent = loginMethod.isAnnotationPresent(Login.class);
if (annotationPresent) {
// 获取注解实例
Login loginAnnotation = loginMethod.getAnnotation(Login.class);
// 获取属性值
String password = loginAnnotation.password();
String username = loginAnnotation.username();
// 打印
System.out.println(password);
System.out.println(username);
}else {
System.out.println("没有使用注解");
}
}
@Login
public static void login(){
}
}
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Login{
// 属性
String username() default "admin";
String password() default "123456";
}
注解的使用场景
在 Java 中,注解被广泛应用于多种场景,提供了一种用于添加元数据到代码中的方式。注解不会直接影响代码的操作,但可以被工具、库和框架用于生成代码、进行编译时检查或在运行时处理。以下是一些常见的 Java 注解使用场景:
- 编译时检查:
- 用于提高代码质量,如
@Override确保方法覆盖,@Deprecated表示方法过时,@SuppressWarnings抑制编译器警告。
- 用于提高代码质量,如
- 框架和库:
- Web 框架如 Spring 使用注解来定义路由、请求方法、依赖注入等,例如
@Controller,@RequestMapping,@Autowired。
- Web 框架如 Spring 使用注解来定义路由、请求方法、依赖注入等,例如
- 测试代码:
- 单元测试框架如 JUnit 使用注解定义测试方法、测试前后的操作,例如
@Test
- 单元测试框架如 JUnit 使用注解定义测试方法、测试前后的操作,例如
- 代码生成:
- 自动生成代码,如 Lombok 库使用
@Getter,@Setter,@AllArgsConstructor等注解来自动生成 getter、setter 方法和构造方法。
- 自动生成代码,如 Lombok 库使用
- 配置和设置:
- 在 Spring 和其他依赖注入框架中,用于配置和设置应用程序,如
@Configuration,@Bean。
- 在 Spring 和其他依赖注入框架中,用于配置和设置应用程序,如
- 拦截器和过滤器:
- 在 AOP(面向切面编程)中,用于定义切点和通知,如
@Aspect,@Before,@After。
- 在 AOP(面向切面编程)中,用于定义切点和通知,如
- 自定义业务逻辑:
- 创建自定义注解来实现特定的业务逻辑,如验证、日志记录、缓存等等。
Java 注解提供了一种强大的机制来简化代码、复用代码、提高可读性和维护性,并支持诸如配置管理、数据校验和框架开发等高级功能。通过注解,开发者可以将关键信息嵌入到代码的声明性部分,而不是执行性代码中。