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 等框架的关键。掌握注解后,你能更深入地理解框架的运行机制,也能按需定义注解来简化业务逻辑、提升代码扩展性。
1520

被折叠的 条评论
为什么被折叠?



