一、Java 注解基础
(一)什么是注解
注解是一种特殊的标记,它可以被添加到包、类、方法、字段等程序元素上,用于为这些元素添加额外的信息。这些信息可以在编译期、运行期被读取和处理,从而实现各种功能,比如代码生成、配置管理、测试框架支持等。
(二)内置注解
Java 提供了一些内置注解,常见的有:
- @Override:用于标识方法是重写父类的方法,编译器会进行检查,确保方法签名正确。
- @Deprecated:表示该元素已过时,使用时编译器会给出警告。
- @SuppressWarnings:抑制编译器警告,例如@SuppressWarnings(“unchecked”)可以抑制类型转换时的 unchecked 警告。
二、元注解
元注解是用于修饰注解的注解,它为注解提供了更多的元数据信息,从而控制注解的行为和使用方式。在 Java 中,主要有以下几种元注解:
(一)@Retention
@Retention 元注解用于指定被修饰注解的保留策略,即该注解在什么阶段存在。RetentionPolicy 有三个取值:
- RetentionPolicy.SOURCE:注解只在源代码中存在,编译时会被丢弃。
- RetentionPolicy.CLASS:注解在编译后的字节码中存在,但运行时 JVM 不会读取,这是默认值。
- RetentionPolicy.RUNTIME:注解在运行时仍然存在,JVM 可以读取,可以通过反射获取注解信息并进行处理。
例如,定义一个运行时保留的注解:
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation { String value() default "";}
(二)@Target
@Target 元注解用于指定被修饰注解可以应用在哪些程序元素上。ElementType 有多个取值,常见的有:
- ElementType.TYPE:可以应用于类、接口、枚举等类型。
- ElementType.METHOD:可以应用于方法。
- ElementType.FIELD:可以应用于字段。
例如,将注解限制为只能应用于方法:
import java.lang.annotation.ElementType;import java.lang.annotation.Target;@Target(ElementType.METHOD)public @interface MyAnnotation { String value() default "";}
(三)@Documented
@Documented 元注解表示被修饰的注解会被 Javadoc 工具记录。如果一个注解被 @Documented 修饰,那么在生成 API 文档时,该注解也会被包含在文档中,方便其他开发者了解使用。
(四)@Inherited
@Inherited 元注解表示被修饰的注解具有继承性。如果一个类使用了被 @Inherited 修饰的注解,那么它的子类也会自动继承该注解。不过需要注意的是,这个继承只针对类,对于接口和方法等并不适用。
(五)@Repeatable
@Repeatable 元注解允许同一个注解在同一个程序元素上被多次使用。在 Java 8 之前,一个程序元素上只能使用一次相同的注解。有了 @Repeatable 后,开发者可以更灵活地使用注解。
三、自定义注解
(一)定义自定义注解
自定义注解通过@interface关键字来定义。例如,定义一个简单的自定义注解@MyAnnotation:
public @interface MyAnnotation { // 注解可以包含成员变量,这里定义一个字符串类型的成员变量 String value() default "";}
在这个例子中,MyAnnotation注解有一个成员变量value,并且设置了默认值为空字符串。
(二)注解的参数
- 语法:参数类型 + 参数名();
- 类型限制:注解的成员变量类型只能是基本类型(如int、double等)、String、Class、enum、Annotation以及这些类型的数组。
- 默认值:可以为成员变量设置默认值,如上面的value变量设置了默认值””。如果不设置默认值,在使用注解时必须显式赋值。
(三)使用自定义注解
@MyAnnotation(value = "Hello, Annotation!")public class MyClass { // 类的内容}
在这个例子中,MyClass类上使用了MyAnnotation注解,并为value成员变量赋值。
(四)注解的保留策略
注解的保留策略决定了注解在什么时候可用,通过Retention元注解来设置。RetentionPolicy有三个取值:
- RetentionPolicy.SOURCE:注解只在源代码中存在,编译时会被丢弃。
- RetentionPolicy.CLASS:注解在编译后的字节码中存在,但运行时 JVM 不会读取,这是默认值。
- RetentionPolicy.RUNTIME:注解在运行时仍然存在,JVM 可以读取,可以通过反射获取注解信息并进行处理。
(五)注解的目标
注解的目标指定了注解可以应用在哪些程序元素上,通过Target元注解来设置。ElementType有多个取值,常见的有:
- ElementType.TYPE:可以应用于类、接口、枚举等类型。
- ElementType.METHOD:可以应用于方法。
- ElementType.FIELD:可以应用于字段。
四、运行时读取注解
当注解的保留策略为RetentionPolicy.RUNTIME时,可以通过反射在运行时读取注解信息。例如:
import java.lang.reflect.Method;
public class AnnotationReader {
public static void main(String[] args) {
try {
Class<?> clazz = MyClass.class;
Method method = clazz.getMethod("myMethod");
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
if (annotation!= null) {
System.out.println("注解的值:" + annotation.value());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
@MyAnnotation(value = "运行时读取")
class MyClass {
public void myMethod() {
// 方法内容
}
}
在这个例子中,通过反射获取MyClass类的myMethod方法上的MyAnnotation注解,并输出注解的值。