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(); // 注解元素,表示 ID
String 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 {
@Override
public void eat() { // 如果方法签名错误,编译器会报错
System.out.println("This dog eats dog food.");
}
}
细节:
@Override
注解用于标记子类方法覆盖了父类方法。- 如果子类方法没有正确覆盖父类方法(例如方法签名不匹配),编译器会报错。
@Deprecated 注解
public class OldClass {
@Deprecated
public 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 {
@Autowired
private 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 {
@LogExecutionTime
public 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
方法来处理注解。