Java学习教程,从入门到精通,Java 注解(Annotations)语法知识点及案例代码(50)

发布于:2024-12-06 ⋅ 阅读:(84) ⋅ 点赞:(0)

1、Java 注解(Annotations)语法知识点及案例代码

Java 注解(Annotations)是 JDK 5 引入的一种语法元素,提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。这些注解不会影响代码的实际逻辑,但可以被一些工具在编译、运行时解析和使用,起到说明、配置的功能。

一、Java 注解的基本语法
  1. 注解的声明

    • 注解以 @ 符号开头。
    • 注解可以包含元素(成员/属性/参数),也可以不包含。
    • 注解的定义看起来和接口的定义很像,但注解的定义使用 @interface 关键字,而不是 interface
  2. 标记注解

    • 标记注解不包含成员/元素,仅用于标记声明。
    • 示例:@Override@Deprecated@SuppressWarnings 等。
  3. 单元素注解

    • 单元素注解仅包含一个元素。
    • 示例:@SuppressWarnings(value = "unchecked")
  4. 多元素注解

    • 多元素注解由逗号分隔的多个元素组成。
    • 示例:@MyAnnotation(element1 = "value1", element2 = "value2")
  5. 注解放置

    • 注解可以放在类、方法、接口、字段和其他程序元素的声明之上。
    • 从 Java 8 开始,注解还可以放在类型之前。
二、Java 内置的标准注解
  1. @Override

    • 表示当前的方法定义将覆盖基类的方法。
    • 如果方法签名拼错了,编译器会报错。
  2. @Deprecated

    • 表示被修饰的类或类成员、类方法已经废弃、过时,不建议使用。
  3. @SuppressWarnings

    • 关闭不当的编译器警告信息。
  4. @FunctionalInterface

    • 表示被修饰的接口是函数式接口(在 JDK 8 引入)。
    • 函数式接口就是一个有且仅有一个抽象方法的接口,但可以有多个非抽象方法(如默认方法、静态方法)。
三、元注解

元注解是用于定义注解的注解,包括 @Retention@Target@Inherited@Documented@Repeatable 等。

  1. @Retention

    • 定义该注解在哪一个级别可用。
    • 可选的 RetentionPolicy 参数包括:SOURCE(只在源文件中保留,编译时丢弃)、CLASS(在类文件中可用,但不会被 JVM 加载)、RUNTIME(在运行时也保留,可以通过反射读取)。
  2. @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);
    }
}
六、代码注释详解
  1. 自定义注解 TestAnnotation

    • @Retention(RetentionPolicy.RUNTIME):表示该注解在运行时也保留,可以通过反射读取。
    • @Target(ElementType.METHOD):表示该注解只能用于方法声明。
    • int id():定义一个 id 元素,没有默认值。
    • String description() default "no description":定义一个 description 元素,有默认值 "no description"
  2. 使用自定义注解的类 TestUtils

    • @TestAnnotation(id = 1, description = "This is a test method"):在 testMethod 方法上使用自定义注解,并指定 iddescription 的值。
  3. 注解处理器 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方法来处理注解。

网站公告

今日签到

点亮在社区的每一天
去签到