Java annotation

  • 注解Annotation
  • 1、Annotation的概述
    • 1.1、定义
    • 1.2、Annotation作用分类
    • 1.3、Annotation 架构
  • 2、Annotation的语法形式
  • 3、Annotation的分类
    • 3.1、基本注解
    • 3.2、元注解
      • 3.2.1、@Target
      • 3.2.2、@Retention
      • 3.2.3、@Documented
      • 3.2.4、@Inherited:
  • 4、自定义annotation
    • 4 .1、定义说明
    • 4.2、实例
  • 参考

注解Annotation

秒懂,Java 注解 (Annotation)你可以这样学

1、Annotation的概述

1.1、定义

注解(Annotation),也叫元数据,是一种代码级别的说明。

它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

其实Annotation就是代码里的特殊标记,它们可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。

注意:Annotation能被用来为程序元素(类、方法、成员变量等)设置元素据。Annotaion不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一地执行。如果希望让程序中的Annotation起一定的作用,只有通过解析工具或编译工具对Annotation中的信息进行解析和处理。

1.2、Annotation作用分类

一般来说,元数据可以用于创建文档(根据程序元素上的注释创建文档),跟踪代码中的依赖性(可声明方法是重载,依赖父类的方法),执行编译时检查(可声明是否编译期检测),代码分析。
如下:

  • 1、编写文档:通过注解生成API文档(@Documented)
  • 2、编译检查:通过注解让编译器实现基本的编译检查(@Override)
  • 3、代码分析:通过注解对代码进行分析【反射等】(重点)

1.3、Annotation 架构


从中,我们可以看出:

  • (1) 1 个 Annotation 和 1 个 RetentionPolicy关联。可以理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性。

  • (2) 1 个 Annotation 和 1~n 个 ElementType 关联。可以理解为:对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性。

  • (3) Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override 等等。 Annotation 的每一个实现类,都 “和 1 个 RetentionPolicy 关联” 并且 " 和 1~n 个 ElementType 关联"。

下面,我先介绍框架图的左半边(如下图),即 Annotation, RetentionPolicy, ElementType;然后在就 Annotation 的实现类进行举例说明。

Annotation 组成部分

java Annotation 的组成中,有 3 个非常重要的主干类。它们分别是:

Annotation.java

package java.lang.annotation;
public interface Annotation {boolean equals(Object obj);int hashCode();String toString();Class<? extends Annotation> annotationType();
}

ElementType.java

package java.lang.annotation;public enum ElementType {TYPE,               /* 类、接口(包括注释类型)或枚举声明  */FIELD,              /* 字段声明(包括枚举常量)  */METHOD,             /* 方法声明  */PARAMETER,          /* 参数声明  */CONSTRUCTOR,        /* 构造方法声明  */LOCAL_VARIABLE,     /* 局部变量声明  */ANNOTATION_TYPE,    /* 注释类型声明  */PACKAGE             /* 包声明  */
}

RetentionPolicy.java

package java.lang.annotation;
public enum RetentionPolicy {SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}

说明:

(1) Annotation 就是个接口。
“每 1 个 Annotation” 都与 “1 个 RetentionPolicy” 关联,并且与 “1~n 个 ElementType” 关联。可以通俗的理解为:每 1 个 Annotation 对象,都会有唯一的 RetentionPolicy 属性;至于 ElementType 属性,则有 1~n 个。

(2) ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型。
“每 1 个 Annotation” 都与 “1~n 个 ElementType” 关联。当 Annotation 与某个 ElementType 关联时,就意味着:Annotation有了某种用途。例如,若一个 Annotation 对象是 METHOD 类型,则该 Annotation 只能用来修饰方法。

(3) RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同。

“每 1 个 Annotation” 都与 “1 个 RetentionPolicy” 关联。

  • a) 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该Annotation 就没用了。 例如," @Override" 标志就是一个Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override"就没有任何作用了。
  • b) 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是Annotation 的默认行为。
  • c) 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class文件中,并且可由JVM读入。

这时,只需要记住"每 1 个 Annotation" 都与 “1 个 RetentionPolicy” 关联,并且与 “1~n 个 ElementType” 关联。

2、Annotation的语法形式

public @interface 注解名称 {}

我们可以定义一个简单的注解,如下:

package com.hanyxx.annotaion;/*** @author xxx* @description: 自定义注解*/
public @interface bocai {}
如果通过 javac命令将注解类编译,然后再通过 javap 命令进行反编译,就会发现:
public interface com.hanyxx.annotaion.bocai extends java.lang.annotation.Annotation {}

注解的本质就是:接口

3、Annotation的分类

java内置了6个基本注解和4个元注解

3.1、基本注解

@Override :检测被该注解标注的方法是继承自父类(接口)的@Deprecated:该注解标注的内容,表示已过时@SuppressWarnings:压制警告其中jdk1.7之后引入了另外两个基本注解:@SafeVarargs : Java7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告@FunctionalInterface : Java8 开始支持,标识一个匿名函数或函数式接口。@Repeatable: Java8 开始支持,标识某注解可以在同一个声明上使用多次其中@Override、@Deprecated、@SuppressWarnings、@SafeVarargs
和@FunctionalInterface在java.lang包下而@Repeatable在java.lang.annotation包下
/*** @Date 2021/11/13 14:04* @Version 10.21* @Author XXX*/
public class AnnotationTest {public static void main(String[] args) {@SuppressWarnings("unused")int a = 10;}@Deprecatedpublic void myPrint(){System.out.println("@Deprecated修饰的方法表示已过时");}@Overridepublic String toString(){return "重写的toString()";}
}

3.2、元注解

元注解(meta-annotation):定义注解的注解

3.2.1、@Target

@Target:用于描述注解能够作用的范围,可取的值存于ElementType枚举类中。

  • 当注解类型声明中没有@Target元注解,则默认为可适用所有的程序元素。如果存在指定的@Target元注解,则编译器强制实施相应的使用限制。

@Target(ElementType.TYPE)
public @interface Table {/*** 数据表名称注解,默认值为类名称* @return*/public String tableName() default "className";
}@Target(ElementType.FIELD)
public @interface NoDBColumn {}

注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。

3.2.2、@Retention

@Retention:指定所修饰的 Annotation 的生命周期:SOURCE\CLASS(默认行为)\RUNTIME只有声明为RUNTIME生命周期的注解,才能通过反射获取。

@Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用@Rentention 时必须为该 value 成员变量指定值:

  • RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释
  • RetentionPolicy.CLASS:在class文件中有效(即class保留) , 当运行 Java 程序时,
    JVM不会保留注解。 这是默认值
  • RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行 Java程序时, JVM会保留注释。程序可以通过反射获取 该注释。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField"; public boolean defaultDBValue() default false;
}

Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理

3.2.3、@Documented

@Documented:用于指定被该元 Annotation 修饰的 Annotation 类将被javadoc 工具提取成文档。默认情况下,javadoc是不包括注解的。

  • 定义为Documented的注解必须设置Retention值为RUNTIME。
@author 标明开发该类模块的作者,多个作者之间使用,分割@version 标明该类模块的版本@see 参考转向,也就是相关主题@since 从哪个版本开始增加的@param 对方法中某参数的说明,如果没有参数就不能写@return 对方法返回值的说明,如果方法的返回值类型是void就不能写@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写其中@param @return 和 @exception 这三个标记都是只用于方法的。@param的格式要求:@param 形参名 形参类型 形参说明@return 的格式要求:@return 返回值类型 返回值说明@exception的格式要求:@exception 异常类型 异常说明@param和@exception可以并列多个
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField"; public boolean defaultDBValue() default false;
}

3.2.4、@Inherited:

@Inherited:被它修饰的 Annotation 将具有 继承性。如果某个类使用了被@Inherited 修饰的 Annotation, 则其子类将自动具有该注解。

  • 比如:如果把标有@Inherited注解的自定义的注解标注在类级别上,子类则可以继承父类类级别的注解。

注意:

@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

/*** * @author test**/
@Inherited
public @interface Greeting {public enum FontColor{ BULE,RED,GREEN};String name();FontColor fontColor() default FontColor.GREEN;
}

4、自定义annotation

4 .1、定义说明

  • 1、定义新的 Annotation 类型使用 @interface 关键字
  • 2、自定义注解自动继承了java.lang.annotation.Annotation 接口
  • 3、Annotation 的成员变量在Annotation定义中以无参数方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。我们称为配置参数。类型只能是八种基本数据类型、String类型、Class 类型 、enum 类型 、Annotation 类型 、以上所有类型的 数组
  • 4、可以在定义 Annotation的成员变量时为其指定初始值, 指定成员变量的初始值可使用 default 关键字
  • 5、如果只有一个参数成员,建议使用 参数名为value
  • 6、如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认值。格式是“参数名 = 参数值”,如果只有一个参数成员,且名称为value,可以省略“value=”
  • 7、没有成员定义的 Annotation 称为 标记; 包含成员变量的 Annotation 称为元数据 Annotation

注意:自定义注解必须配上注解的信息处理流程才有意义。

package com.hanyxx.annotaion;
import java.lang.annotation.*;
/*** @author 菠菜饭团* @description: 自定义注解*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface BoCai {String name() default "XXX";ElementType[] value() default ElementType.TYPE ;String className();String methodName();
}
package com.hanyxx.annotaion;
import java.lang.reflect.Method;
/*** @author XXX* @description: 通过注解的形式创建任意对象,并且执行任意方法*/
@BoCai(className="com.hanyxx.annotaion.PlayGame",methodName = "play")
public class AnnotationTest {public static void main(String[] args) throws Exception {/***  <A extends Annotation> A getAnnotation(Class<A> annotationClass) :如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。*  Annotation[] getAnnotations() : 返回此元素上存在的所有注解。*///1.获取类字节码对象Class<AnnotationTest> annotationClass = AnnotationTest.class;//2.获取该类的注解对象(本质是在内存中生成该注解接口的子类实现对象)BoCai boCai = annotationClass.getAnnotation(BoCai.class);//3.获取传入的类名和方法名String className = boCai.className();System.out.println("获取类名:"+className);System.out.println("===========================");String methodName = boCai.methodName();System.out.println("获取方法名:"+methodName);System.out.println("===========================");//4.加载类进内存,并获取方法对象Class<?> Cls = Class.forName(className);Method method = Cls.getMethod(methodName);//5.创建对象实例并调用方法Object o = Cls.newInstance();method.invoke(o);}
}

4.2、实例

MyAnnotation

package com.atguigu.java1;import java.lang.annotation.*;import static java.lang.annotation.ElementType.*;@Inherited
@Repeatable(MyAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
public @interface MyAnnotation {String value() default "hello";
}

MyAnnotations

package com.atguigu.java1;import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
public @interface MyAnnotations {MyAnnotation[] value();
}

AnnotationTest

package com.atguigu.java1;import org.junit.Test;import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Date;/*** 注解的使用** 1. 理解Annotation:* ① jdk 5.0 新增的功能** ② Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation,* 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。** ③在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android* 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗* 代码和XML配置等。** 2. Annocation的使用示例* 示例一:生成文档相关的注解* 示例二:在编译时进行格式检查(JDK内置的三个基本注解)@Override: 限定重写父类方法, 该注解只能用于方法@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择@SuppressWarnings: 抑制编译器警告* 示例三:跟踪代码依赖性,实现替代配置文件功能** 3. 如何自定义注解:参照@SuppressWarnings定义* ① 注解声明为:@interface* ② 内部定义成员,通常使用value表示* ③ 可以指定成员的默认值,使用default定义* ④ 如果自定义注解没有成员,表明是一个标识作用。如果注解有成员,在使用注解时,需要指明成员的值。自定义注解必须配上注解的信息处理流程(使用反射)才有意义。自定义注解通过都会指明两个元注解:Retention、Target4. jdk 提供的4种元注解元注解:对现有的注解进行解释说明的注解Retention:指定所修饰的 Annotation 的生命周期:SOURCE\CLASS(默认行为)\RUNTIME只有声明为RUNTIME生命周期的注解,才能通过反射获取。Target:用于指定被修饰的 Annotation 能用于修饰哪些程序元素*******出现的频率较低*******Documented:表示所修饰的注解在被javadoc解析时,保留下来。Inherited:被它修饰的 Annotation 将具有继承性。5.通过反射获取注解信息 ---到反射内容时系统讲解6. jdk 8 中注解的新特性:可重复注解、类型注解6.1 可重复注解:① 在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class② MyAnnotation的Target和Retention等元注解与MyAnnotations相同。6.2 类型注解:ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如:泛型声明)。ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。**/
public class AnnotationTest {public static void main(String[] args) {Person p = new Student();p.walk();Date date = new Date(2020, 10, 11);System.out.println(date);@SuppressWarnings("unused")int num = 10;//        System.out.println(num);@SuppressWarnings({ "unused", "rawtypes" })ArrayList list = new ArrayList();}@Testpublic void testGetAnnotation(){Class clazz = Student.class;Annotation[] annotations = clazz.getAnnotations();for(int i = 0;i < annotations.length;i++){System.out.println(annotations[i]);}}
}//jdk 8之前的写法:
//@MyAnnotations({@MyAnnotation(value="hi"),@MyAnnotation(value="hi")})
@MyAnnotation(value="hi")
@MyAnnotation(value="abc")
class Person{private String name;private int age;public Person() {}@MyAnnotationpublic Person(String name, int age) {this.name = name;this.age = age;}@MyAnnotationpublic void walk(){System.out.println("人走路");}public void eat(){System.out.println("人吃饭");}
}interface Info{void show();
}class Student extends Person implements Info{@Overridepublic void walk() {System.out.println("学生走路");}public void show() {}
}class Generic<@MyAnnotation T>{public void show() throws @MyAnnotation RuntimeException{ArrayList<@MyAnnotation String> list = new ArrayList<>();int num = (@MyAnnotation int) 10L;}}

参考

1、https://www.cnblogs.com/Tanyboye/p/9138412.html
2、Java 注解(Annotation)

Java:annotation注解的简单理解和总结相关推荐

  1. java 数据校验框架_自己写的基于java Annotation(注解)的数据校验框架

    JavaEE6中提供了基于java Annotation(注解)的Bean校验框架,Hibernate也有类似的基于Annotation的数据校验功能,我在工作中,产品也经常需要使 用数据校验,为了方 ...

  2. Java Annotation(注解)使用教程

    Java Annotation(注解)使用教程 1 什么是注解 2 注解的使用语法 2.1 内置注解介绍以及使用 @Override @Deprecated @SuppressWarnings @Sa ...

  3. @configurationproperties注解的使用_SpringBoot常用注解的简单理解

    不定时更新... 文章目录 Spring容器 JavaBean POJO @Autowired @Controller @Resource @RestController @Service @Repo ...

  4. Java关键字synchronized的简单理解

    参考链接: https://blog.csdn.net/luoweifu/article/details/46613015 Java中并发编程使用中,最频繁和最简单的使用是synchronized关键 ...

  5. 对java中接口的简单理解

    接口属于一个特殊的抽象类,继承的时候用 implements 实现,接口的继承不叫继承,叫做实现 接口的实现和类的继承有些类似,但是类的继承是单继承,接口可以多实现(多继承) 类的继承是对共性的继承, ...

  6. java中的二进制运算简单理解

    package test9;public class StreamTest {public static void main(String[] args) {int a = 15;// 0b1111i ...

  7. 让别人和自己看懂自己的程序代码?一文掌握Java单行多行、文档注释以及注解(Annotation)超详细的理解使用,IDEA注释注解快捷键和模板,提高程序代码更有可读性

    文章目录 单行和多行注释 文档注释(Java特有) Annotation(注解)的理解 常见的Annotation示例 IDEA注释注解快捷键及模板 自定义 Annotation JDK 中的元注解 ...

  8. Java Annotation认知(包括框架图、详细介绍、示例说明)

    摘要 Java Annotation是JDK5.0引入的一种注释机制. 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annotation本来很简单的,结果说的人没说清楚 ...

  9. 深入理解Java:注解(Annotation)--注解处理器

    如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了.使用注解的过程中,很重要的一部分就是创建于使用注解处理器.Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处 ...

最新文章

  1. 嫌弃YouTube推荐算法,这位小哥决定自己动手写代码来推荐视频
  2. 大系统化小之后,微信如何解决大规模微服务下的难题?
  3. python做电脑软件-作为一个Python程序员,电脑上应该具备哪些软件?
  4. codeforce 603B - Moodular Arithmetic
  5. 胖子哥大数据之路(一)-数据仓库也需要大数据
  6. 【树莓派】为Ubuntu for ARM 更换中国软件源
  7. AWS如何迁移实例到另一个区?
  8. 一次共享内存引起的线上事故分析
  9. python基础(part5)--容器类型之字符串
  10. php 地址获取百度经纬度,根据百度api获取一个地址的经纬度
  11. 鸡啄米vc++2010系列25(滚动条控件Scroll Bar)
  12. 异贝,通过移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例28
  13. 线性代数张宇9讲 第六讲 线性方程组
  14. stm32 ov2640硬件软件笔记
  15. 如何搭建监狱高清1080P OTT/IPTV电视系统
  16. 支持向量机原理小结(3)——核方法和非线性支持向量机
  17. 开心网kaixin001状告kaixin,停用“开心网”名称,赔偿1000万元并公开道歉
  18. docker中安装nacos报错 com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
  19. C++字符串大小写转换
  20. URL Extractor 4 for Mac(URL资源地址抓取器)特别版

热门文章

  1. C++中的void*理解
  2. Kickstarter开源了其移动应用程序,面向小型企业的OpenOffice,以及更多新闻
  3. two-stream双流网络 知乎、CSDN学习笔记
  4. 3DMAX模型导出到Unity之中如何确保材质不丢失
  5. abstract 是什么意思?
  6. html代码name是什么意思,JavaScript中nodeName是什么意思?
  7. Python中计算图像亮度
  8. BZOJ 1822 浅谈计算几何在网络流建模中的实际运用
  9. AFOACM begin
  10. 老生常谈之--修内功还是打把势