1. 概述
本文将深入探讨 Java 语言的核心特性之一——JDK 中提供的内置注解。这些注解是 Java 开发中不可或缺的工具,掌握它们能显著提升代码质量和开发效率。
2. 什么是注解
简单来说,注解就是以 "@" 符号开头的 Java 类型。
自 Java 1.5 版本引入注解后,它彻底改变了我们设计应用程序的方式。Spring 和 Hibernate 等框架就是重度依赖注解的典型例子。
本质上,注解为绑定的源代码附加额外元数据。通过在方法、接口、类或字段上添加注解,我们可以:
- ✅ 向编译器提供警告和错误信息
- ✅ 在编译时操作源代码
- ✅ 在运行时修改或检查行为
3. Java 内置注解
现在让我们看看 JDK 自带的核心注解。首先是编译相关注解:
-
@Override
-
@SuppressWarnings
-
@Deprecated
-
@SafeVarargs
-
@FunctionalInterface
-
@Native
这些注解用于生成或抑制编译器警告和错误。建议规范使用它们,能有效避免未来潜在的错误。
3.1. @Override
@Override
注解用于明确标记方法覆盖父类行为。虽然不强制使用,但加上它能:
- ✅ 防止拼写错误导致的意外重载
- ✅ 提高代码可读性
3.2. @SuppressWarnings
@SuppressWarnings
用于忽略特定代码段的编译警告。常见场景包括:
- 使用泛型时的未检查类型警告
- 已弃用 API 的警告
⚠️ 建议谨慎使用,仅当确认警告无害时才抑制。
3.3. @Deprecated
@Deprecated
用于标记不再建议使用的 API。Java 9 后还增强了该注解:
@Deprecated(since = "1.2", forRemoval = true)
public void oldMethod() {}
3.4. @FunctionalInterface
Java 8 引入函数式编程后,单抽象方法接口(SAM) 变得重要。使用 @FunctionalInterface
可明确意图:
@FunctionalInterface
public interface Adder {
int add(int a, int b);
}
即使不加注解,Adder
仍可作为 lambda 使用:
Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);
但若误添加第二个方法:
@FunctionalInterface
public interface Adder {
// 编译器会报错:不是 SAM 接口
int add(int a, int b);
int div(int a, int b);
}
核心价值:像 @Override
一样,将错误局限在接口定义处,避免扩散到所有使用点。
3.5. @Native
Java 8 新增的 @Native
仅适用于字段,表示该常量可能被本地代码引用。典型用法:
public final class Integer {
@Native public static final int MIN_VALUE = 0x80000000;
// 省略其他代码
}
该注解还能辅助工具生成头文件。
4. 元注解
元注解是用于注解其他注解的注解。Java 提供了五个元注解:
-
@Target
-
@Retention
-
@Inherited
-
@Documented
-
@Repeatable
4.1. @Target
定义注解的适用范围,支持 12 种元素类型。查看 @SafeVarargs
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}
❌ 错误示例:若注解未限定 @Target
,可能导致误用。
4.2. @Retention
控制注解的生命周期,三种策略:
-
RetentionPolicy.SOURCE
– 仅源码可见 -
RetentionPolicy.CLASS
– 编译时可见(默认) -
RetentionPolicy.RUNTIME
– 运行时可见
示例:
@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface RuntimeAnnotation {}
测试验证:
@Test
public void testRuntimeRetention() {
Annotation[] annotations = new AnnotatedClass().getClass().getAnnotations();
assertThat(annotations.length, is(1)); // 仅 RUNTIME 注解被保留
}
4.3. @Inherited
使注解自动被子类继承。示例:
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {}
@InheritedAnnotation
public class BaseClass {}
public class DerivedClass extends BaseClass {}
验证:
@Test
public void testInheritance() {
InheritedAnnotation annotation = new DerivedClass()
.getClass()
.getAnnotation(InheritedAnnotation.class);
assertThat(annotation, notNullValue());
}
⚠️ 注意:仅对类注解有效,接口/方法注解不继承。
4.4. @Documented
将注解纳入 Javadoc。示例:
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCell {
int value();
}
public class Employee {
@ExcelCell(0)
public String name;
}
生成的 Javadoc 会显示字段注解:
4.5. @Repeatable
允许在同一元素重复使用注解。Java 7 前需要容器注解:
@Schedules({
@Schedule(time = "15:05"),
@Schedule(time = "23:00")
})
void scheduledAlarm() {}
Java 8 引入 @Repeatable
后简化为:
@Repeatable(Schedules.class)
public @interface Schedule {
String time() default "09:00";
}
public @interface Schedules {
Schedule[] value();
}
// 使用时无需显式容器
@Schedule
@Schedule(time = "15:05")
@Schedule(time = "23:00")
void scheduledAlarm() {}
✅ 迁移友好:旧代码可直接升级为新用法。
5. 总结
本文系统梳理了 Java 内置注解体系,包括:
- 编译相关注解(
@Override
、@Deprecated
等) - 元注解(
@Target
、@Retention
等) - Java 8+ 新增特性(
@FunctionalInterface
、@Repeatable
)
掌握这些注解能帮助开发者:
- ✅ 编写更健壮的代码
- ✅ 避免"踩坑"
- ✅ 提升框架开发能力
本文所有示例代码可在 GitHub 获取。