tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java基础与面向对象

    • Java中的一些概念
    • Java中的数组
    • String类跟关键字final
    • Java 日期时间与Date
    • Java中的异常处理
    • Java枚举
    • Java序列化和反序列化
    • Java中的注解
      • 说明
      • 注解的基本概念
      • 注解的作用
        • 自定义注解
        • 一个例子
        • 应用自定义注解
        • 利用注解
        • 实际用途
      • 自定义注解的属性
        • 基本数据类型和 String 类型
        • Class 类型
        • 枚举类型
        • 其他注解类型
        • 数组类型
        • 注意事项
    • Java中的IO流
    • Java中抽象类与接口
  • 高级进阶

  • 并发合集

  • JVM合集

  • 实战与细节

  • 代码之丑与提升

  • 《Java》学习笔记
  • Java基础与面向对象
EffectTang
2024-12-18
目录

Java中的注解

# Java中的注解

# 说明

注解(Annotations)是一种元数据形式,它提供了关于程序代码的额外信息,但这些信息并不直接改变程序的执行逻辑。注解自Java 5引入以来,已经成为Java编程不可或缺的一部分。它们可以被用来标记类、方法、变量、参数、包声明等元素,并且可以在编译时、类加载时或运行时通过反射机制读取。

# 注解的基本概念

  • 定义:注解以@符号开头,后跟注解名称。例如,@Override。

  • 类型:注解分为:

    • 标准注解(如@Override, @Deprecated, @SuppressWarnings)、

    • 元注解(用于定义其他注解,如@Retention, @Target, @Documented, @Inherited),

    • 以及自定义注解。

# 注解的作用

  1. 编译检查:
    • 注解可用于编译期检查代码的正确性。例如,@Override注解用于确保你所标注的方法确实是在重写超类中的方法。如果方法签名不匹配,则会在编译时给出错误提示。
  2. 生成文档:
    • 虽然JavaDoc标签也能提供类似功能,但注解能够更灵活地为代码添加描述信息。例如,@Deprecated注解用来标记那些不建议使用的方法或类,并且可以通过JavaDoc工具生成相应的文档说明。
  3. 代码分析:
    • 开发者可以创建自定义注解并利用工具进行静态代码分析,以检测潜在的问题或遵循特定的编码规范。
  4. 框架支持:
    • 许多现代Java框架(如Spring, Hibernate等)都大量使用了注解来简化配置和提高生产力。例如,在Spring框架中,@Component, @Service, @Controller等注解用于自动装配Bean。
  5. 运行时处理:
    • 使用反射API可以在运行时读取注解信息,从而实现动态行为调整。比如基于注解的安全检查、日志记录等功能。

# 自定义注解

开发者可以根据需求定义自己的注解,这通常涉及到使用元注解来指定注解的行为:

  • @Retention: 指定注解保留策略(源码级别、类文件级别、运行时)。
  • @Target: 定义该注解可以应用的目标元素类型(如方法、字段、类等)。
  • @Documented: 表示此注解应包含在生成的文档中。
  • @Inherited: 标识某个注解类型会被自动继承到子类中。

其中关于target和Retention是最为常用的2种。

而其中,Target,支持的常见 ElementType 类型,有如下几种

类型 用途
TYPE 类、接口、枚举
METHOD 方法
FIELD 属性(字段)
CONSTRUCTOR 构造方法
PARAMETER 方法参数

可以单独使用,也可以组合使用

@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MultiUseAnnotation {
  
}
1
2
3
4

# 一个例子

首先,我们有一个自定义注解的定义:

import java.lang.annotation.*;

// 定义一个自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnnotation {
    String value() default "default value";
}
1
2
3
4
5
6
7
8

这里有几个关键点需要注意:

  • @Retention(RetentionPolicy.RUNTIME):这表示该注解将在运行时保留,这意味着可以通过反射在运行时读取它。
  • @Target(ElementType.METHOD):限制了该注解只能应用于方法上。
  • String value() default "default value";:这是注解的一个元素,允许用户指定一个字符串值,默认为"defualt value"。

# 应用自定义注解

然后,在你的类中使用这个注解:

public class MyClass {
    @TestAnnotation(value = "Hello, World")
    public void myMethod() {
        // 方法体
    }
}
1
2
3
4
5
6

在这个例子中,myMethod() 被标记了@TestAnnotation注解,并且指定了注解元素value的值为 "Hello, World"。

# 利用注解

为了使这个注解发挥作用,你需要编写一些逻辑来利用它。通常,这涉及到使用Java的反射API来检查是否有方法被特定注解标记,并根据注解中的信息执行相应的操作。以下是一个简单的示例,展示如何在运行时检测并处理带有@TestAnnotation的方法:

import java.lang.reflect.Method;

public class AnnotationProcessor {
    public static void main(String[] args) {
        try {
            Class<?> clazz = MyClass.class;
            for (Method method : clazz.getDeclaredMethods()) {
                if (method.isAnnotationPresent(TestAnnotation.class)) {
                    TestAnnotation annotation = method.getAnnotation(TestAnnotation.class);
                    System.out.println("Method: " + method.getName());
                    System.out.println("Annotation Value: " + annotation.value());
                    
                    // 可以在这里添加更多基于注解的逻辑
                    // 例如,调用该方法、记录日志等
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 实际用途

  1. 元数据查询:可以用来获取方法或类的额外信息,比如作者、版本号等。
  2. 自动化测试框架:像JUnit这样的框架会扫描所有带有特定注解的方法,并自动执行这些方法作为测试用例。
  3. AOP(面向切面编程):用于识别需要横切关注点(如事务管理、安全检查)的方法,并在不修改原始业务逻辑的情况下插入这些功能。
  4. 依赖注入框架:Spring等框架使用注解来配置依赖关系,减少XML配置的需求。

# 自定义注解的属性

自定义注解中的属性并不仅限于String类型,实际上可以使用多种数据类型。Java允许在注解中使用以下几种类型的属性:

  1. 基本数据类型:包括 int, long, short, byte, char, double, float, boolean。
  2. String 类型。
  3. Class 类型:例如 Class<?> 或 Class<SomeType>。
  4. 枚举类型:任何已定义的枚举类型都可以作为注解的属性类型。
  5. 其他注解类型:一个注解可以作为一个属性的类型。
  6. 以上类型的一维数组形式:例如 int[], String[], Class<?>[] 等。

这里有几个示例展示如何在自定义注解中使用不同的属性类型:

# 基本数据类型和 String 类型

public @interface Performance {
    int timeout(); // 基本数据类型
    String description() default "No description provided"; // String 类型,默认值
}
1
2
3
4

# Class 类型

public @interface ComponentScan {
    Class<?>[] basePackages(); // Class 类型数组
}
1
2
3

# 枚举类型

假设你有一个枚举类型:

public enum LogLevel {
    INFO, WARN, ERROR
}
1
2
3

然后可以在注解中使用它:

public @interface LogConfig {
    LogLevel level() default LogLevel.INFO; // 枚举类型,默认值
}
1
2
3

# 其他注解类型

如果你有另一个注解:

public @interface Dependency {
    String name();
    String version();
}
1
2
3
4

你可以将其用作注解的属性类型:

public @interface ModuleConfig {
    Dependency[] dependencies(); // 注解类型数组
}
1
2
3

# 数组类型

public @interface CacheConfig {
    String[] cacheNames(); // 字符串数组
    Class<?>[] supportedTypes(); // Class 类型数组
}
1
2
3
4

# 注意事项

  • 当定义默认值时,确保提供的默认值与属性类型相匹配。

  • 对于数组类型的属性,如果希望提供一个默认的空数组而不是null,可以这样做:

    public @interface Example {
        String[] names() default {};
    }
    
    1
    2
    3

通过灵活使用这些不同类型的属性,你可以创建功能强大且表达力强的自定义注解来满足各种编程需求。

在定义注解时,属性的声明后面需要加上一对圆括号()。这是Java注解语法的一部分,用来表示这是一个属性声明而不是其他东西。即使属性没有默认值,也需要加上这对括号。

上次更新: 2025/05/24, 08:26:28
Java序列化和反序列化
Java中的IO流

← Java序列化和反序列化 Java中的IO流→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式