作为Java后端开发程序员,掌握JDK原生注解是基础且重要的技能。以下按照功能和类型分类,详细介绍必须掌握的JDK原生注解。
一、编译器提示类注解
这类注解主要用于给编译器提供额外信息,帮助开发者避免常见错误。
1. @Override
作用:标记方法是重写父类或实现接口的方法,如果方法签名不匹配,编译器会报错。
// 定义父类
class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
// 子类重写父类方法
class Dog extends Animal {
// 使用 @Override 注解确保正确重写
@Override
public void makeSound() {
System.out.println("汪汪汪!");
}
// 如果错误地写成makeSound(String sound),编译器会报错
// @Override
// public void makeSound(String sound) { // 编译错误:没有重写父类方法
// System.out.println(sound);
// }
}
2. @Deprecated
作用:标记类、方法或字段已过时,不推荐使用。使用时编译器会给出警告。
public class OldUtility {
// 标记为过时的方法
@Deprecated
public static void oldMethod() {
System.out.println("这是过时的方法,请使用newMethod()");
}
// 推荐使用的新方法
public static void newMethod() {
System.out.println("这是推荐使用的新方法");
}
// 也可以为过时的元素提供替代方案说明
@Deprecated(since = "1.8", forRemoval = true)
public static void legacyMethod() {
System.out.println("这个方法将在未来版本中移除");
}
}
3. @SuppressWarnings
作用:抑制编译器警告,避免不必要的警告信息干扰开发。
import java.util.*;
public class SuppressWarningsExample {
public static void main(String[] args) {
// 抑制"rawtypes"警告(使用原始类型)
@SuppressWarnings("rawtypes")
List list = new ArrayList(); // 不指定泛型类型
// 抑制"unchecked"警告(类型转换不安全)
@SuppressWarnings("unchecked")
List<String> stringList = (List<String>) getList();
// 抑制多个警告类型
@SuppressWarnings({"unchecked", "rawtypes"})
Map map = new HashMap();
System.out.println("警告已被抑制");
}
private static List getList() {
return Arrays.asList("a", "b", "c");
}
}
二、元注解(用于定义其他注解的注解)
元注解是用来注解其他注解的注解,是自定义注解的基础。
1. @Target
作用:指定注解可以应用的程序元素类型。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
// 定义一个只能用于方法的注解
@Target(ElementType.METHOD)
@interface MethodOnlyAnnotation {
String value() default "";
}
// 定义一个可以用于类和方法的注解
@Target({ElementType.TYPE, ElementType.METHOD})
@interface ClassAndMethodAnnotation {
String description() default "";
}
// 使用示例
@ClassAndMethodAnnotation(description = "这是一个测试类")
class TestClass {
@MethodOnlyAnnotation("测试方法")
@ClassAndMethodAnnotation(description = "测试方法描述")
public void testMethod() {
// 方法实现
}
// 以下代码会编译错误,因为 @MethodOnlyAnnotation 不能用于字段
// @MethodOnlyAnnotation
// private String field; // 编译错误
}
2. @Retention
作用:指定注解的保留策略(源码、编译时、运行时)。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 只在源码中保留,编译后丢弃
@Retention(RetentionPolicy.SOURCE)
@interface SourceOnlyAnnotation {
String value() default "";
}
// 编译时保留,包含在class文件中,但运行时不可见
@Retention(RetentionPolicy.CLASS)
@interface ClassRetentionAnnotation {
String value() default "";
}
// 运行时保留,可以通过反射获取
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeAnnotation {
String name() default "";
int version() default 1;
}
// 运行时注解使用示例
@RuntimeAnnotation(name = "UserService", version = 2)
class UserService {
@RuntimeAnnotation(name = "saveUser", version = 1)
public void saveUser(String username) {
System.out.println("保存用户: " + username);
}
}
3. @Documented
作用:指定注解是否包含在JavaDoc文档中。
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 这个注解会被包含在JavaDoc中
@Documented
@Retention(RetentionPolicy.RUNTIME)
@interface PublicAPI {
String value() default "这是一个公共API";
}
// 这个注解不会被包含在JavaDoc中(默认行为)
@Retention(RetentionPolicy.RUNTIME)
@interface InternalAPI {
String value() default "内部API,不对外公开";
}
// 使用示例
@PublicAPI("用户服务公共接口")
class DocumentedExample {
@PublicAPI("获取用户信息")
public String getUserInfo() {
return "用户信息";
}
@InternalAPI("内部处理逻辑")
private void internalProcess() {
// 内部处理
}
}
4. @Inherited
作用:指定注解是否可以被子类继承。
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 使用 @Inherited,子类会继承父类的这个注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface InheritedAnnotation {
String value() default "";
}
// 不使用 @Inherited,子类不会继承父类的这个注解
@Retention(RetentionPolicy.RUNTIME)
@interface NonInheritedAnnotation {
String value() default "";
}
@InheritedAnnotation("父类注解")
@NonInheritedAnnotation("父类非继承注解")
class ParentClass {
// 父类实现
}
class ChildClass extends ParentClass {
// 子类实现
// ChildClass会自动拥有@InheritedAnnotation注解
// 但不会拥有@NonInheritedAnnotation注解
}
// 测试继承效果
class InheritanceTest {
public static void main(String[] args) {
// 检查子类是否继承了注解
if (ChildClass.class.isAnnotationPresent(InheritedAnnotation.class)) {
System.out.println("子类继承了@InheritedAnnotation");
}
if (ChildClass.class.isAnnotationPresent(NonInheritedAnnotation.class)) {
System.out.println("子类继承了@NonInheritedAnnotation");
} else {
System.out.println("子类没有继承@NonInheritedAnnotation");
}
}
}
5. @Repeatable (Java 8+)
作用:允许在同一位置重复使用同一个注解。
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 定义重复注解的容器
@Retention(RetentionPolicy.RUNTIME)
@interface Authorities {
Authority[] value();
}
// 定义可重复的注解
@Repeatable(Authorities.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Authority {
String role();
}
// 使用重复注解
@Authority(role = "ADMIN")
@Authority(role = "USER")
@Authority(role = "GUEST")
class MultiRoleService {
public void accessResource() {
System.out.println("多角色访问控制");
}
}
// 测试重复注解
class RepeatableTest {
public static void main(String[] args) {
Authority[] authorities = MultiRoleService.class.getAnnotationsByType(Authority.class);
System.out.println("角色数量: " + authorities.length);
for (Authority auth : authorities) {
System.out.println("角色: " + auth.role());
}
}
}
三、函数式接口相关注解
@FunctionalInterface (Java 8+)
作用:标记接口为函数式接口(只包含一个抽象方法的接口),编译器会验证接口是否符合函数式接口的要求。
@FunctionalInterface
interface Calculator {
// 函数式接口只能有一个抽象方法
int calculate(int a, int b);
// 可以包含默认方法
default void printResult(int result) {
System.out.println("计算结果: " + result);
}
// 可以包含静态方法
static void showInfo() {
System.out.println("这是一个计算器接口");
}
}
// 错误示例:以下代码会编译错误,因为有两个抽象方法
// @FunctionalInterface
// interface InvalidFunctionalInterface {
// void method1();
// void method2(); // 编译错误:函数式接口只能有一个抽象方法
// }
// 使用函数式接口
class FunctionalInterfaceExample {
public static void main(String[] args) {
// 使用Lambda表达式实现函数式接口
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
int result1 = add.calculate(10, 20);
add.printResult(result1);
int result2 = multiply.calculate(5, 6);
multiply.printResult(result2);
}
}
四、空值检查相关注解 (Java 8+)
这些注解主要用于静态分析工具,帮助检测潜在的空指针异常。
1. @Nullable
2. @NonNull
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
// 注意:严格来说,@Nullable和@NonNull不是JDK原生注解,
// 而是来自Checker Framework,但Java 8+的Optional类提供了类似功能
import java.util.Optional;
class NullSafetyExample {
// 使用Optional来避免空值问题(JDK原生方式)
public Optional<String> findUserName(int userId) {
// 模拟查找用户,可能找不到
if (userId == 1) {
return Optional.of("张三");
} else {
return Optional.empty(); // 返回空的Optional,而不是null
}
}
// 安全地使用Optional
public void processUser(int userId) {
Optional<String> userName = findUserName(userId);
// 方式1:检查是否存在
if (userName.isPresent()) {
System.out.println("找到用户: " + userName.get());
} else {
System.out.println("用户不存在");
}
// 方式2:提供默认值
String name = userName.orElse("默认用户");
System.out.println("用户名称: " + name);
// 方式3:执行操作(如果存在)
userName.ifPresent(nameStr -> System.out.println("处理用户: " + nameStr));
}
}
五、综合使用示例
下面是一个综合使用多种注解的实际例子:
import java.lang.annotation.*;
import java.lang.reflect.Method;
// 自定义注解:用于标记需要权限验证的方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface RequirePermission {
String[] roles() default {"USER"};
boolean checkLogin() default true;
}
// 服务类
class SecureService {
@RequirePermission(roles = {"ADMIN", "MANAGER"}, checkLogin = true)
@Override
public String toString() {
return "安全服务实例";
}
@RequirePermission(roles = {"USER"})
public void normalOperation() {
System.out.println("执行普通操作");
}
@Deprecated(since = "2.0")
public void oldOperation() {
System.out.println("执行过时的操作");
}
}
// 注解处理器(模拟权限检查)
class AnnotationProcessor {
public static void main(String[] args) throws Exception {
Class<?> serviceClass = SecureService.class;
SecureService service = new SecureService();
// 遍历所有方法,检查 @RequirePermission 注解
for (Method method : serviceClass.getDeclaredMethods()) {
if (method.isAnnotationPresent(RequirePermission.class)) {
RequirePermission permission = method.getAnnotation(RequirePermission.class);
System.out.println("方法: " + method.getName());
System.out.println("需要角色: " + String.join(", ", permission.roles()));
System.out.println("需要登录: " + permission.checkLogin());
System.out.println("---");
// 模拟执行方法
if (method.getParameterCount() == 0) {
method.invoke(service);
}
}
}
}
}
总结
必须掌握的核心注解:
-
编译器提示类:
@Override:确保正确重写@Deprecated:标记过时API@SuppressWarnings:抑制编译警告
-
元注解:
@Target:指定注解使用位置@Retention:指定注解保留策略@Documented:控制JavaDoc包含@Inherited:控制注解继承@Repeatable:支持重复注解
-
函数式编程:
@FunctionalInterface:标记函数式接口
学习建议:
- 优先掌握:
@Override、@Deprecated、@SuppressWarnings这三个是最常用的 - 理解原理:元注解是自定义注解的基础,必须理解其工作原理
- 实践应用:在实际项目中尝试使用这些注解,特别是运行时注解配合反射
- 注意版本:某些注解需要特定的Java版本(如
@Repeatable需要Java 8+)
掌握这些JDK原生注解,不仅能写出更规范、更安全的代码,还能为后续学习Spring等框架的注解机制打下坚实基础。

1122

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



