Java 进阶:注解机制深度解析

Java-day21

一、注解与注释的本质区别

| 特性 | 注释(Comment)| 注解(Annotation)|

|--|--|--|

| 作用对象 | 给**人**看,解释代码逻辑 | 给**程序**看,让程序理解代码 |

| 处理阶段 | 仅在编码阶段有效 | 可在编译、类加载、运行时生效 |

| 典型示例 | // 这是一行注释 | @Override、@Deprecated |

**核心**:注释不影响程序运行,仅用于代码说明;注解会被程序(编译器、JVM、框架)解析,直接影响程序行为。

二、Java 注解的分类与核心概念

2.1 内置注解(Java 原生支持)

Java 内置了三类常用注解,无需额外定义即可使用:

(1)@Override

- **作用**:标记方法是对父类方法的重写,编译器会校验重写的正确性(如方法签名是否一致)。

- **示例**:

```java

class Animal {

public void eat() {}

}

class Cat extends Animal {

@Override

public void eat() { // 编译器校验是否真的重写了父类的 eat 方法

System.out.println("猫吃鱼");

}

}

```

(2)@Deprecated

- **作用**:标记类、方法、字段为“已过时”,编译器会给出警告(提示开发者避免使用)。

- **示例**:

```java

@Deprecated

public class OldUtil {

@Deprecated

public void oldMethod() {}

}

// 使用过时类或方法时,编译器会警告

OldUtil util = new OldUtil();

util.oldMethod();

```

(3)@SuppressWarnings

- **作用**:抑制编译器的特定警告(如未检查的类型转换、未使用的变量等)。

- **示例**:

```java

@SuppressWarnings("unchecked")

public void test() {

List list = new ArrayList();

list.add("Java");

List strList = (List) list; // 抑制“未检查的类型转换”警告

}

```

2.2 元注解(用于定义注解的注解)

元注解是“注解的注解”,用于**自定义注解的规则**(如作用范围、生命周期)。Java 提供 4 种元注解:

(1)@Target

- **作用**:指定自定义注解可以修饰的**元素范围**(如类、方法、字段等),取值来自枚举类 ElementType。

- **常用取值**:

- ElementType.TYPE:修饰类、接口、枚举;

- ElementType.METHOD:修饰方法;

- ElementType.FIELD:修饰字段;

- ElementType.CONSTRUCTOR:修饰构造器;

- ElementType.PARAMETER:修饰方法参数;

- **示例**:

```java

import java.lang.annotation.ElementType;

import java.lang.annotation.Target;

// 自定义注解 @MyAnnotation 只能修饰“类”和“方法”

@Target({ElementType.TYPE, ElementType.METHOD})

public @interface MyAnnotation {

}

```

(2)@Retention

- **作用**:指定自定义注解的**生命周期**(即注解在哪个阶段有效),取值来自枚举类 RetentionPolicy。

- **常用取值**:

- RetentionPolicy.SOURCE:仅在源代码阶段有效(编译后消失);

- RetentionPolicy.CLASS:在类文件(.class)中保留(类加载时丢弃);

- RetentionPolicy.RUNTIME:在运行时阶段保留(可通过反射获取);

- **示例**:

```java

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

// 自定义注解 @MyRuntimeAnnotation 在运行时阶段保留

@Retention(RetentionPolicy.RUNTIME)

public @interface MyRuntimeAnnotation {

}

```

(3)@Documented

- **作用**:标记注解会被 javadoc 工具提取到文档中(一般用得较少)。

(4)@Inherited

- **作用**:标记注解可被**子类继承**(即父类的注解会被子类继承)。

2.3 自定义注解(用户按需定义)

开发者可基于元注解,定义满足业务需求的自定义注解。

(1)定义自定义注解的语法

```java

// 元注解:指定作用范围和生命周期

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Value {

// 注解的“属性”:数据类型 + 参数名(),可指定默认值

String name() default "";

}

```

(2)使用自定义注解

```java

public class Cat {

// 在字段上使用自定义注解 @Value,并指定属性值

@Value(name = "小猫")

private String name;

@Value(name = "黑色")

private String color;

@Value(name = "18")

private Integer age;

// 省略 getter/setter 和 toString

}

```

(3)通过反射读取注解信息

```java

import java.lang.reflect.Field;

public class AnnotationTest {

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

Class catClass = Cat.class;

Field[] fields = catClass.getDeclaredFields();

for (Field field : fields) {

// 判断字段是否被 @Value 注解修饰

if (field.isAnnotationPresent(Value.class)) {

Value valueAnno = field.getDeclaredAnnotation(Value.class);

System.out.println(field.getName() + " 的注解属性 name:" + valueAnno.name());

}

}

}

}

```

**输出**:

name 的注解属性 name:小猫

color 的注解属性 name:黑色

age 的注解属性 name:18

三、注解的实战应用:模拟框架注解逻辑

以“自定义 @WebServlet 注解 + 反射解析”为例,模拟 Servlet 框架的路由映射逻辑。

3.1 定义 @WebServlet 注解

```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 WebServlet {

String urlMapping() default "";

}

```

3.2 定义 Servlet 类并使用注解

```java

@WebServlet(urlMapping = "/user/list")

public class UserServlet {

public void doGet() {

System.out.println("处理 /user/list 的 GET 请求");

}

}

```

3.3 通过反射解析注解,模拟路由匹配

```java

import java.lang.reflect.Method;

public class ServletContainer {

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

// 模拟请求 URL

String requestUrl = "/user/list";

// 加载 Servlet 类

Class servletClass = UserServlet.class;

// 读取 @WebServlet 注解的 urlMapping 属性

WebServlet webServletAnno = servletClass.getDeclaredAnnotation(WebServlet.class);

String servletUrl = webServletAnno.urlMapping();

// 匹配 URL,执行对应方法

if (requestUrl.equals(servletUrl)) {

UserServlet servlet = servletClass.newInstance();

Method doGetMethod = servletClass.getDeclaredMethod("doGet");

doGetMethod.invoke(servlet);

}

}

}

```

**输出**:

处理 /user/list 的 GET 请求

四、注解的优缺点与适用场景

4.1 优点

- **解耦**:通过注解配置替代硬编码,降低模块间依赖;

- **灵活**:可在运行时动态解析注解,实现“按需执行”的逻辑;

- **标准化**:框架(如 Spring、MyBatis)通过注解统一规范,提升开发效率。

4.2 缺点

- **性能开销**:反射解析注解会带来一定性能损耗;

- **可读性**:过度使用注解会让代码逻辑分散,可读性下降;

- **调试难度**:注解逻辑隐式执行,调试时需关注注解解析流程。

4.3 适用场景

- **框架开发**:如 Spring 的 @Controller、@Service,MyBatis 的 @Mapper;

- **代码生成**:如 Lombok 的 @Data 自动生成 getter/setter;

- **权限校验**:如自定义 @RequiresPermission 注解实现接口权限控制;

- **单元测试**:如 JUnit 的 @Test 标记测试方法。

五、总结:注解机制核心要点

1. **注解分类**:

- 内置注解:@Override、@Deprecated 等 Java 原生支持;

- 元注解:@Target、@Retention 等用于定义注解的规则;

- 自定义注解:基于元注解,用户按需定义的业务注解。

2. **核心元注解**:

- @Target:指定注解的作用范围(类、方法、字段等);

- @Retention:指定注解的生命周期(源码、类文件、运行时)。

3. **注解与反射的结合**:

自定义注解需在 RUNTIME 阶段保留,再通过反射(getDeclaredAnnotation()、isAnnotationPresent() 等)读取注解信息,实现动态逻辑。

注解是 Java 进阶的重要知识点,是理解 Spring、MyBatis 等框架的关键。掌握注解后,你能更深入地理解框架的运行机制,也能按需定义注解来简化业务逻辑、提升代码扩展性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值