1、Java 注解(Annotations)语法知识点及案例代码
Java 注解(Annotations)是 JDK 5 引入的一种语法元素,提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。这些注解不会影响代码的实际逻辑,但可以被一些工具在编译、运行时解析和使用,起到说明、配置的功能。
一、Java 注解的基本语法
-
注解的声明:
- 注解以
@
符号开头。 - 注解可以包含元素(成员/属性/参数),也可以不包含。
- 注解的定义看起来和接口的定义很像,但注解的定义使用
@interface
关键字,而不是interface
。
- 注解以
-
标记注解:
- 标记注解不包含成员/元素,仅用于标记声明。
- 示例:
@Override
、@Deprecated
、@SuppressWarnings
等。
-
单元素注解:
- 单元素注解仅包含一个元素。
- 示例:
@SuppressWarnings(value = "unchecked")
。
-
多元素注解:
- 多元素注解由逗号分隔的多个元素组成。
- 示例:
@MyAnnotation(element1 = "value1", element2 = "value2")
。
-
注解放置:
- 注解可以放在类、方法、接口、字段和其他程序元素的声明之上。
- 从 Java 8 开始,注解还可以放在类型之前。
二、Java 内置的标准注解
-
@Override:
- 表示当前的方法定义将覆盖基类的方法。
- 如果方法签名拼错了,编译器会报错。
-
@Deprecated:
- 表示被修饰的类或类成员、类方法已经废弃、过时,不建议使用。
-
@SuppressWarnings:
- 关闭不当的编译器警告信息。
-
@FunctionalInterface:
- 表示被修饰的接口是函数式接口(在 JDK 8 引入)。
- 函数式接口就是一个有且仅有一个抽象方法的接口,但可以有多个非抽象方法(如默认方法、静态方法)。
三、元注解
元注解是用于定义注解的注解,包括 @Retention
、@Target
、@Inherited
、@Documented
、@Repeatable
等。
-
@Retention:
- 定义该注解在哪一个级别可用。
- 可选的
RetentionPolicy
参数包括:SOURCE
(只在源文件中保留,编译时丢弃)、CLASS
(在类文件中可用,但不会被 JVM 加载)、RUNTIME
(在运行时也保留,可以通过反射读取)。
-
@Target:
- 定义注解可以用于哪些地方。
- 可选的
ElementType
参数包括:CONSTRUCTOR
(构造器声明)、FIELD
(字段声明)、LOCAL_VARIABLE
(局部变量声明)、METHOD
(方法声明)、PACKAGE
(包声明)、PARAMETER
(参数声明)、TYPE
(类、接口、注解类型或枚举声明)。
四、自定义注解
用户可以根据自己的需求定义注解。自定义注解的定义也需要使用元注解来修饰。
五、案例代码
// 自定义注解
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留
@Target(ElementType.METHOD) // 注解只能用于方法声明
public @interface TestAnnotation {int id(); // 注解元素,表示 IDString description() default "no description"; // 注解元素,表示描述,有默认值
}// 使用自定义注解的类
public class TestUtils {// 在方法上使用注解@TestAnnotation(id = 1, description = "This is a test method")public void testMethod() {System.out.println("Executing test method...");}
}// 注解处理器,用于读取并处理注解
import java.lang.reflect.Method;public class TestAnnotationTracker {public static void trackTestAnnotation(Class<?> cl) {for (Method m : cl.getDeclaredMethods()) {TestAnnotation ta = m.getAnnotation(TestAnnotation.class);if (ta != null) {System.out.println("ID: " + ta.id());System.out.println("Description: " + ta.description());}}}public static void main(String[] args) {trackTestAnnotation(TestUtils.class);}
}
六、代码注释详解
-
自定义注解
TestAnnotation
:@Retention(RetentionPolicy.RUNTIME)
:表示该注解在运行时也保留,可以通过反射读取。@Target(ElementType.METHOD)
:表示该注解只能用于方法声明。int id()
:定义一个id
元素,没有默认值。String description() default "no description"
:定义一个description
元素,有默认值"no description"
。
-
使用自定义注解的类
TestUtils
:@TestAnnotation(id = 1, description = "This is a test method")
:在testMethod
方法上使用自定义注解,并指定id
和description
的值。
-
注解处理器
TestAnnotationTracker
:trackTestAnnotation(Class<?> cl)
:遍历指定类的所有方法,查找并使用反射机制读取TestAnnotation
注解的信息。main(String[] args)
:测试注解处理器,传入TestUtils.class
作为参数。
以下是一些关于Java注解的额外示例和细节:
示例一:编译时注解的使用
@Override 注解
class Animal {public void eat() {System.out.println("This animal eats food.");}
}class Dog extends Animal {@Overridepublic void eat() { // 如果方法签名错误,编译器会报错System.out.println("This dog eats dog food.");}
}
细节:
@Override
注解用于标记子类方法覆盖了父类方法。- 如果子类方法没有正确覆盖父类方法(例如方法签名不匹配),编译器会报错。
@Deprecated 注解
public class OldClass {@Deprecatedpublic void oldMethod() {System.out.println("This method is deprecated.");}
}public class Main {public static void main(String[] args) {OldClass obj = new OldClass();obj.oldMethod(); // 编译器会发出警告,提示该方法已过时}
}
细节:
@Deprecated
注解用于标记已过时的方法、类或字段。- 当使用过时的元素时,编译器会发出警告。
示例二:运行时注解的使用
@Autowired 注解(Spring框架)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class MyService {public void serve() {System.out.println("Service is serving.");}
}@Component
public class MyController {@Autowiredprivate MyService myService;public void execute() {myService.serve();}
}
细节:
@Autowired
注解用于实现依赖注入。- 在Spring框架中,
@Autowired
可以自动将匹配的依赖对象注入到目标对象中。 @Component
注解用于标记类为组件,使其能够被Spring的组件扫描机制自动发现并创建实例。
@RequestMapping 注解(Spring MVC框架)
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class MyController {@RequestMapping("/hello")public String hello() {return "Hello, World!";}
}
细节:
@RequestMapping
注解用于将请求映射到处理器方法上。- 在Spring MVC框架中,
@RequestMapping
可以定义URL路径与处理器方法的映射关系。 @RestController
注解是@Controller
和@ResponseBody
的结合体,用于创建RESTful风格的控制器。
示例三:自定义注解及其处理
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
使用自定义注解
public class MyService {@LogExecutionTimepublic void performTask() throws InterruptedException {Thread.sleep(1000); // 模拟任务执行时间System.out.println("Task completed.");}
}
注解处理器
import java.lang.reflect.Method;public class AnnotationProcessor {public static void processAnnotations(Object obj) throws Exception {Method[] methods = obj.getClass().getDeclaredMethods();for (Method method : methods) {if (method.isAnnotationPresent(LogExecutionTime.class)) {long startTime = System.currentTimeMillis();method.invoke(obj);long endTime = System.currentTimeMillis();System.out.println("Execution time: " + (endTime - startTime) + " ms");}}}public static void main(String[] args) throws Exception {MyService myService = new MyService();processAnnotations(myService); // 自动处理带有@LogExecutionTime注解的方法,并记录执行时间}
}
细节:
- 自定义注解
@LogExecutionTime
用于标记需要记录执行时间的方法。 - 注解处理器
AnnotationProcessor
通过反射机制遍历对象的方法,查找并处理带有@LogExecutionTime
注解的方法。 - 在
main
方法中,创建MyService
对象并调用processAnnotations
方法来处理注解。