Appearance
注解
注解简介
什么是注解?
注解(Annotation)是 Java 5 引入的特性,用于为代码添加元数据,不直接影响代码执行。
┌─────────────────────────────────────────────────────────────────┐
│ 注解的三个生命周期 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. SOURCE → 仅存在于源码,编译时丢弃 │
│ 示例:@Override, @SuppressWarnings │
│ │
│ 2. CLASS → 编译时保留,运行时丢弃(.class文件中) │
│ 用于:编译时处理,不影响运行时 │
│ │
│ 3. RUNTIME → 运行时保留,可通过反射获取 │
│ 示例:@Autowired, @Transactional │
│ │
└─────────────────────────────────────────────────────────────────┘Java 内置注解
常用注解
| 注解 | 作用域 | 生命周期 | 说明 |
|---|---|---|---|
| @Override | 方法 | SOURCE | 标记重写父类方法 |
| @Deprecated | 方法/类 | RUNTIME | 标记已过时 |
| @SuppressWarnings | 方法/类 | SOURCE | 抑制编译器警告 |
| @FunctionalInterface | 接口 | SOURCE | 标记函数式接口 |
| @SafeVarargs | 方法 | RUNTIME | 抑制可变参数警告 |
| @Retention | 注解 | SOURCE | 指定注解生命周期 |
| @Target | 注解 | SOURCE | 指定注解作用目标 |
@Override 示例
java
public class Parent {
public void display() {
System.out.println("Parent display");
}
}
public class Child extends Parent {
@Override // 编译检查,确保确实重写了父类方法
public void display() {
System.out.println("Child display");
}
// @Override 编译错误:拼写错误,方法签名不匹配
// public void displa() { }
}@SuppressWarnings 示例
java
// 抑制所有警告
@SuppressWarnings("all")
public void method1() { }
// 抑制未检查警告(泛型相关)
@SuppressWarnings("unchecked")
public void method2() {
List list = new ArrayList(); // raw type
list.add("test");
}
// 抑制弃用警告
@SuppressWarnings("deprecation")
public void method3() {
Date date = new Date(); // Date 已弃用
}
// 抑制多种警告
@SuppressWarnings({"unchecked", "deprecation"})
public void method4() { }元注解(注解的注解)
@Retention
java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 源码级别保留
@Retention(RetentionPolicy.SOURCE)
public @interface SourceOnly { }
// 编译时保留
@Retention(RetentionPolicy.CLASS)
public @interface ClassOnly { }
// 运行时保留(可反射)
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeRetention { }@Target
java
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
// 只能作用于方法
@Target(ElementType.METHOD)
public @interface MethodOnly { }
// 作用于多种目标
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public @interface MultiTarget { }
// 注解所有目标(除 PACKAGE)
@Target(ElementType.TYPE_USE)
public @interface AllTypes { }ElementType 枚举值
| 值 | 说明 | 示例 |
|---|---|---|
| TYPE | 类、接口、枚举 | @MyAnnotation |
| FIELD | 字段 | @MyAnnotation |
| METHOD | 方法 | @MyAnnotation |
| PARAMETER | 参数 | @MyAnnotation |
| CONSTRUCTOR | 构造器 | @MyAnnotation |
| LOCAL_VARIABLE | 局部变量 | @MyAnnotation |
| ANNOTATION_TYPE | 注解类型 | @MyAnnotation |
| PACKAGE | 包 | @MyAnnotation |
@Inherited
java
@Inherited // 子类继承父类的此注解
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation { }
@InheritedAnnotation
public class Parent { }
public class Child extends Parent { } // 自动拥有 @InheritedAnnotation自定义注解
基本定义
java
import java.lang.annotation.*;
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
// 注解属性(类似接口方法)
String value(); // 必须属性
int number() default 0; // 带默认值的属性
String[] tags() default {}; // 数组属性
}
// 使用
public class Test {
@MyAnnotation(value = "test", number = 10, tags = {"tag1", "tag2"})
public void method() { }
}完整示例
java
// ==================== 定义注解 ====================
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface ApiDoc {
String description() default "";
String author() default "unknown";
String version() default "1.0";
String[] tags() default {};
}
// ==================== 使用注解 ====================
@ApiDoc(
description = "用户登录接口",
author = "张三",
version = "2.0",
tags = {"登录", "用户"}
)
public class UserController {
@ApiDoc(description = "登录方法")
public Result login(String username, String password) {
// 登录逻辑
return Result.success();
}
}
// ==================== 读取注解 ====================
public class AnnotationProcessor {
public static void main(String[] args) throws Exception {
// 读取类上的注解
ApiDoc classDoc = UserController.class.getAnnotation(ApiDoc.class);
if (classDoc != null) {
System.out.println("类:" + classDoc.description());
System.out.println("作者:" + classDoc.author());
}
// 读取方法上的注解
Method[] methods = UserController.class.getDeclaredMethods();
for (Method method : methods) {
ApiDoc methodDoc = method.getAnnotation(ApiDoc.class);
if (methodDoc != null) {
System.out.println("方法:" + method.getName());
System.out.println("描述:" + methodDoc.description());
}
}
}
}注解与反射
获取注解信息
java
// ==================== 注解定义 ====================
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequirePermission {
String[] value();
}
// ==================== 使用注解 ====================
public class UserService {
@RequirePermission({"admin", "user:read"})
public void getUserInfo(Long userId) {
System.out.println("获取用户信息");
}
@RequirePermission({"admin"})
public void deleteUser(Long userId) {
System.out.println("删除用户");
}
}
// ==================== 权限校验框架 ====================
public class SecurityChecker {
public static void checkPermission(Object target, String methodName) {
Class<?> clazz = target.getClass();
try {
// 获取方法
Method method = clazz.getDeclaredMethod(methodName);
// 获取注解
RequirePermission perm = method.getAnnotation(RequirePermission.class);
if (perm == null) {
System.out.println("方法无需权限");
return;
}
// 获取当前用户权限(模拟)
Set<String> userPermissions = getCurrentUserPermissions();
// 检查权限
for (String required : perm.value()) {
if (!userPermissions.contains(required)) {
throw new SecurityException("缺少权限:" + required);
}
}
System.out.println("权限校验通过");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private static Set<String> getCurrentUserPermissions() {
// 模拟从Session获取当前用户权限
return new HashSet<>(Arrays.asList("user:read", "user:write"));
}
}
// 测试
public class Test {
public static void main(String[] args) {
UserService userService = new UserService();
SecurityChecker.checkPermission(userService, "getUserInfo");
SecurityChecker.checkPermission(userService, "deleteUser");
}
}常用框架注解
Spring 注解
java
// ==================== 组件标注 ====================
@Component // 通用组件标注
@Service // 服务层组件
@Repository // 持久层组件
@Controller // 控制层组件(Web)
@RestController // @Controller + @ResponseBody
// ==================== 依赖注入 ====================
@Autowired // 自动注入(byType)
@Qualifier("name") // 指定注入 bean 名称
@Resource(name="") // 相当于 @Autowired + @Qualifier
@Inject // JSR-330 标准注解
// ==================== 请求处理 ====================
@RequestMapping // 请求映射
@GetMapping // GET 请求
@PostMapping // POST 请求
@PutMapping // PUT 请求
@DeleteMapping // DELETE 请求
@PathVariable // 路径变量
@RequestParam // 请求参数
// ==================== 配置 ====================
@Configuration // 配置类
@Bean // Bean 定义
@Value // 注入配置值
@PropertySource // 加载配置文件Lombok 注解
java
// ==================== 数据生成 ====================
@Data // getter/setter/toString/equals/hashCode
@Getter // 生成 getter
@Setter // 生成 setter
@ToString // 生成 toString
@EqualsAndHashCode // 生成 equals 和 hashCode
// ==================== 构造方法 ====================
@NoArgsConstructor // 无参构造
@AllArgsConstructor // 全参构造
@RequiredArgsConstructor // 必需参数构造(final 和 @NonNull)
// ==================== 建造者模式 ====================
@Builder // 生成建造者模式
@Builder.Default // 建造者默认值
// ==================== 日志 ====================
@Log // private static final org.slf4j.Logger
@Slf4j
@Log4j
@Log4j2
// ==================== 其他 ====================
@NonNull // 生成 null 检查
@Cleanup // 自动关闭资源
@SneakyThrows // 偷偷抛出异常使用示例
java
// Lombok 示例
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NonNull
private Long id;
private String name;
@Builder.Default
private Integer age = 0;
@ToString.Exclude
private String password;
}
// 使用
User user = User.builder()
.id(1L)
.name("张三")
.age(25)
.build();
System.out.println(user.getName()); // 自动生成 getter注解处理器(编译时)
APT 示例
java
// ==================== 注解定义 ====================
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.CLASS)
public @interface AutoGenerateService {
}
// ==================== 注解处理器 ====================
@SupportedAnnotationTypes("com.example.AutoGenerateService")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class ServiceAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(
AutoGenerateService.class)) {
TypeElement typeElement = (TypeElement) element;
String className = typeElement.getSimpleName().toString();
String packageName = getPackageName(typeElement);
// 生成服务类代码
String generatedCode = generateServiceCode(packageName, className);
// 写入文件
writeToFile(packageName, className + "Service", generatedCode);
}
return true;
}
private String getPackageName(TypeElement typeElement) {
return processingEnv.getElementUtils()
.getPackageOf(typeElement).getQualifiedName().toString();
}
private String generateServiceCode(String packageName, String className) {
return "package " + packageName + ";\n" +
"public class " + className + "Service {\n" +
" // Generated code\n" +
"}\n";
}
}总结
注解核心知识点:
| 知识点 | 面试频率 | 实战重要性 |
|---|---|---|
| @Retention 生命周期 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| @Target 作用目标 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 自定义注解 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 注解与反射 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Spring/Lombok 注解 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
⚠️ 易错点提醒:
@Retention(RetentionPolicy.RUNTIME)才能通过反射获取- 注解属性不能是复杂类型(如
List<T>),只能是基本类型、String、Class、枚举、注解、数组 - 注解属性有默认值时,使用注解时可以省略
- 注解不支持继承,但可以使用@Inherited让子类继承
- 注解不能作用于自己的声明(递归)