[Java]自定义注解

简介: 本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://developer.aliyun.com/article/1632620
出自【进步*于辰的博客

由于单独的一个或多个元注解无法进行测试,故本篇文章中的示例都是基于自定义注解。因此,大家在阅读代码时,可能会觉得有点云里雾里。无妨,疑惑是暂时的。

启发博文:《自定义注解详细介绍》(转发)。
参考笔记一,P72.1、P76.1。

注: 本篇文章引入了两个知识点,会在举例时使用。

  1. 反射,详述可查阅博文《[Java]反射》;
  2. JavaDoc文档,推荐一篇博文《【Java学习笔记】【基础篇】07.JavaDoc以及两种使用方式》(转发)。

1、四个元注解

1.1 @target

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
   
    ElementType[] value();
}

指定所标注的注解可标注于哪些java元素(如:类、属性、方法等),value的取值可自行查看源码。

在不指定value时,表示所标注的注解可标注于任何java元素。此时,会根据所标注的注解所标注的元素类型自适应具体的ElementType

示例:

@Target({
   ElementType.TYPE, ElementType.FIELD})// 可用于注解类和属性
@interface SelfAnno {
   }

@SelfAnno// 通过
class TestAnno {
   
    @SelfAnno// 通过
    private Integer id;

    @SelfAnno // 报错
    public void test() {
   }
}

1.2 @Retention

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
   
    RetentionPolicy value();
}

指定所标注的注解的生命周期value有三个取值:SOURCECLASSRUNTIME,默认为CLASS

值说明:

  1. SOURCE:表示所标注的注解只保留在 java 源文件(xx.java)中,JVM不会进行编译。
  2. CLASS:表示所标注的注解会被编译到 class 字节码文件(xx.class)中,但JVM会忽略,即无法获取。
  3. RUNTIME:表示所标注的注解会被编译到JVM中,可通过反射获取,实际开发中的自定义注解的生命周期几乎都是这个。

    1.3 @Documented

    源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

指定所标注的注解将跟随java文件到JavaDoc文档中。

1.4 @Inherited

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
   
}

指定所标注的注解是否可被所标注的类的子类继承此注解。

示例。

@Target({
   ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface SelfAnno {
   
    String sign();
}

class TestAnno {
   
    @SelfAnno(sign = "type")
    class C {
   
        @SelfAnno(sign = "method")
        public void test() {
   }
    }

    class SubC extends C {
   }

    public static void main(String[] args) throws Exception {
   
        Class clazz  = C.class;
        sout getSign(clazz.getAnnotation(SelfAnno.class));// type
        sout getSign(clazz.getMethod("test").getAnnotation(SelfAnno.class));// method

        clazz = SubC.class;
        sout getSign(clazz.getAnnotation(SelfAnno.class));// type
        sout getSign(clazz.getMethod("test").getAnnotation(SelfAnno.class));// method
    }

    private static String getSign(Annotation anno) {
   
        return ((SelfAnno)anno).sign();
    }
}

标注于类、或者方法上的注解都可以被继承。

2、自定义注解

2.1 介绍

所有注解都自动继承java.lang.annotation.Annotation接口,注解由@interface声明,上述源码中的value()是注解元素,类似于成员属性。

注解元素必须由()结尾,可以使用default定义默认值,使用注解时必须为所有无默认值的注解元素赋值。

举个例:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@interface SelfAnno {
   
    String platform() default "博客平台";
    String name();
}

@SelfAnno(platform = "云平台", name = "CSDN")// platform = "云平台" 可省略
class Csdn {
   }

注意

  1. 注解元素必须由public修饰,默认是public
  2. 一般注解元素以名词命名,若只有一个,建议名称为value
  3. 注解元素类型只能是基本数据类型、基本数据类型数组或注解类型(注解嵌套);
  4. default指定注解元素默认值时,值类型必须与注解元素类型相同。

    2.2 使用细节

  5. 若无注解元素,可省略()(小括号);
  6. 若注解元素类型为数组,且赋值时只有一个值时,可以省略{}(花括号);
  7. 如果只有一个注解元素,且注解元素名为value。无论其是什么类型,都可省略前缀xx =)。
  8. ElementTypePACKAGE,则此注解用于标注在package-info.java文件中。:这个文件默认是不创建的。在idea中,双击shift可搜索到,打开时才会创建。其用途尚未可知,而不是类文件(xx.java)的第一行的package...上。

    3、@AliasFor

    Spring提供的这个注解为注解的使用带来了很大的便利。

启发博文:《详解@AliasFor注解的使用与注意事项》(转发)。

这篇文章说明得很详细,我便不赘述,仅作两点小结:

  1. 注解内:成对存在且相互映射,返回值类型与默认值必须相同。标注时若都指定,值必须相同。
  2. 注解间:需先标注,返回值类型必须相同。

    最后

    本文中的示例是为了方便大家理解自定义注解的定义和使用方法而简单举出的,不一定有实用性,旨在抛砖引玉。大家阅读完后,可能仍有疑惑,不妨自行测试一下,就都理解了。

另外,自定义注解时可使用“静态导入”(import static),会更简便。

本文完结。

相关文章
|
27天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
50 1
|
8天前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
39 7
|
27天前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
30 1
|
2月前
|
Java
让星星⭐月亮告诉你,自定义定时器和Java自带原生定时器
定时器是一种可以设置多个具有不同执行时间和间隔的任务的工具。本文介绍了定时器的基本概念、如何自定义实现一个定时器,以及Java原生定时器的使用方法,包括定义定时任务接口、实现任务、定义任务处理线程和使用Java的`Timer`与`TimerTask`类来管理和执行定时任务。
53 3
|
5天前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
61 34
|
2月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
97 43
Java学习十六—掌握注解:让编程更简单
|
13天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
45 5
|
1月前
|
前端开发 Java
[Java]讲解@CallerSensitive注解
本文介绍了 `@CallerSensitive` 注解及其作用,通过 `Reflection.getCallerClass()` 方法返回调用方的 Class 对象。文章还详细解释了如何通过配置 VM Options 使自定义类被启动类加载器加载,以识别该注解。涉及的 VM Options 包括 `-Xbootclasspath`、`-Xbootclasspath/a` 和 `-Xbootclasspath/p`。最后,推荐了几篇关于 ClassLoader 的详细文章,供读者进一步学习。
33 12
|
2月前
|
安全 Java
如何在 Java 中创建自定义安全管理器
在Java中创建自定义安全管理器需要继承SecurityManager类并重写其方法,以实现特定的安全策略。通过设置系统安全属性来启用自定义安全管理器,从而控制应用程序的访问权限和安全行为。
52 1
|
2月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
62 2
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下