[Java]自定义注解

简介: [Java]自定义注解

1、常见元注解

1.1 @target

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

作用:用于指定被注解的注解能注解于哪些 java 元素上(如:类、属性、方法等),类型为枚举ElementType[](关于枚举ElementType的具体取值,大家可自行查看源码)。在不指定具体ElementType时,表示被注解的注解可注解于任何 java 元素。此时,会根据被注解的注解所注解的类型自适应具体的ElementType

示例:

@Target({ElementType.TYPE,
        ElementType.FIELD})// --------A
@interface MyAnnotation {
}
@MyAnnotation// ----------------------B
class TestAnnotation {
    @MyAnnotation// ------------------D
    private Integer id;
    @MyAnnotation// ------------------D
    public void print() {
    }
}

A处指定ElementTypeTYPEFIELD,表示@MyAnnotation 可用于注解类和属性,因此,B、C 处编译通过,而 D 处编译报错。

若将 A 删除,则 B、C、D 三处都编译通过,因为@MyAnnotation@Target会根据@MyAnnotation所注解的类型自适应具体的ElementType

1.2 @Retention

源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

作用:指定被注解的注解的生命周期,类型为枚举RetentionPolicy,有三个值可选:SOURCECLASSRUNTIME。当不指定RetentionPolicy时,默认为CLASS

值说明:

  1. SOURCE:表示被注解的注解只保留在 java 源文件中(后缀是.java的文件),JVM不会进行编译;
  2. CLASS:表示被注解的注解能被编译到 class 文件中(后缀是.class的文件,即 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 {
}

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

示例。

情形一:(没有定义@Inherited

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
}
@MyAnnotation
class Person {
}
class Teacher extends Person {
}
public class TestAnnotation {
    public static void main(String[] args) throws Exception {
        Class personClass = Class.forName("com.neusoft.boot.Person");// 使用反射,通过全限定名获取Class对象
        Class teacherClass = Class.forName("com.neusoft.boot.Teacher");
        MyAnnotation a1 = (MyAnnotation) personClass.getAnnotation(MyAnnotation.class);// 获取注解在类Person上的@MyAnnotation
        sout a1;// 打印:@com.neusolt.boot.MyAnnotation()
        MyAnnotation a2 = (MyAnnotation) teacherClass.getAnnotation(MyAnnotation.class);// 获取注解在类Teacher上的@MyAnnotation
        sout a2;// 打印:null
    }
}

情形二:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
}
@MyAnnotation
class Person {
}
class Teacher extends Person {
}
public class TestAnnotation {
    public static void main(String[] args) throws Exception {
        Class personClass = Class.forName("com.neusoft.boot.Person");
        Class teacherClass = Class.forName("com.neusoft.boot.Teacher");
        MyAnnotation a1 = (MyAnnotation) personClass.getAnnotation(MyAnnotation.class);
        sout a1;// 打印:@com.neusolt.boot.MyAnnotation()
        MyAnnotation a2 = (MyAnnotation) teacherClass.getAnnotation(MyAnnotation.class);
        sout a2;// 打印:@com.neusolt.boot.MyAnnotation()
    }
}

2、自定义注解

上文中常见元注解的示例都是基于自定义注解,相信大家对自定义注解已有了初步了解。

2.1 概述

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

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

举个例:

@Target(ElementType.TYPE)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface MyAnnotation {
    String name() default "cs";
}
@MyAnnotation(name = "csdn")// 这里的 (name = "csdn") 可省略
class Person {
}

注解@MyAnnotation有一个注解元素name,默认值为"cs"。由于name有默认值,故使用此注解时不必须为name赋值。

2.2 注意事项

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

2.3 使用细节

  1. 若无注解元素,可省略()(小括号);
  2. 若注解元素类型为数组,且赋值时只有一个值时,可以省略{}(花括号);
  3. 如果只有一个注解元素,且注解元素名为value。无论其是什么类型,都可省略前缀。如上述例子:需要name = "csdn"为注解元素name赋值,如果注解元素名为value,则可省略“value =”;
  4. ElementTypePACKAGE,则此注解用于注解在package-info.java文件中(PS:这个文件默认是不创建的。在idea中,双击shift可搜索到,打开时才会创建。其用途尚未可知,欢迎大家留言!),而不是类文件(xx.java)的第一行的package...上。

4、最后

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

本文完结。

相关文章
|
2月前
|
Java Spring 容器
【Java】Spring如何扫描自定义的注解?
【Java】Spring如何扫描自定义的注解?
36 0
|
2月前
|
Java 数据库连接
hibernate注解实体类(Dept.java)
hibernate注解实体类(Dept.java)
13 1
|
2月前
|
Java 数据库连接
Hibernate中使用Criteria查询及注解——(Dept.java)
Hibernate中使用Criteria查询及注解——(Dept.java)
15 1
|
2月前
|
存储 Java API
【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了(一)
【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了
26 1
|
2月前
|
存储 SQL Java
【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了(二)
【Java技术指南】「JPA编程专题」让你不再对JPA技术中的“持久化型注解”感到陌生了
45 1
|
1天前
|
算法 安全 Java
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
【4月更文挑战第28天】性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
10 0
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
|
4天前
|
Java 关系型数据库 MySQL
万字长文带你详聊Java注解本质
万字长文带你详聊Java注解本质
12 0
|
8天前
|
Java 测试技术 编译器
JAVA注解
JAVA注解
10 0
|
19天前
|
Java
Java配置大揭秘:读取自定义配置文件的绝佳指南
Java配置大揭秘:读取自定义配置文件的绝佳指南
17 0
Java配置大揭秘:读取自定义配置文件的绝佳指南
|
23天前
|
NoSQL Java Redis
Java自定义线程池的使用
Java自定义线程池的使用