注解,也叫元数据,是一种代码级别的说明。它是JDK1.5引入的一个特性,与类、接口、枚举类所在同一个层次。它可以声明在包、类、方法、成员变量、构造器、局部变量、方法参数等的上面,用来对这些元素进行说明、注释。也可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。

1、注解的作用分类

(1)生成文档相关的注释说明:通过代码里标识的注解可以生成文档相关的注释说明。

下面我们就来演示一下,首先我们编写一个类,添加相关的注解。

/*** @author Mr.wu* @version 1.0* @since 1.8*/
public class AnnotationDemo {/**** @param a* @param b* @return a+b*/public int sum(int a,int b){return a+b;}
}

然后使用javadoc指令把我们创建的类生成javadoc文档。

生成之后,如下图所示:

打开文档,如下图所示:

我们平时使用的JDK的文档就是这样生成的。

(2)分析运行代码:通过代码里标识的注解对代码进行分析运行[使用反射]。
最后会进行演示。

(3)编译检查:通过代码里的注解让编译器实现编译检查。
例如:我们平时经常使用的override注解,当我们使用此注解时,编译器就会检查该方法是否重写了父类(或接口)中的方法。

2、JDK内置注解

JDK中内置了三个基本的注解,下面就来介绍一下:

  1. @Override: 限定重写父类中方法, 该注解只能用于方法;

  2. @Deprecated: 用于表示所修饰的元素(类, 方法等)已过时,通常是因为所修饰的结构危险或存在更好的选择;

  3. @SuppressWarnings: 抑制编译器警告。

3、JDK中的元注解

元注解就是修饰注解的注解。JDK中有四个元注解:

  1. @Target:表示注解能够作用的位置。

    (1) ElementType.TYPE :可以作用在类、接口和枚举类上;
    (2) ElementType.METHOD :可以作用在方法上;
    (3) ElementType.FIELD :可以作用在成员变量上;
    (4) ElementType.CONSTRUCTOR :可以作用在构造器上;
    (5) ElementType.LOCAL_VARIABLE :可以作用在局部变量上。

  2. @Retention:表示注解的生命周期,即注解被保留的阶段。

    (1) RetentionPolicy.SOURCE :在源文件中有效(即源文件保留),编译时编译器会直接丢弃这种策略的注解;
    (2) RetentionPolicy.CLASS : 在class文件中有效(即class保留),当运行Java程序时, JVM不会保留注解。这是默认值
    (3) RetentionPolicy.RUNTIME : 在运行时有效(即运行时保留),当运行 Java 程序时, JVM会保留注解。程序可以通过反射获取该注释。

  3. @Documented:表示该注解修饰的注解,可以被抽取到API文档中。
    注意:定义为Documented的注解必须设置Retention值为RetentionPolicy.RUNTIME 。

  4. @Inherited:表示该注解可以被子类继承。

4、自定义注解

自定义注解很简单,格式为:

   元注解public @interface 注解

自定义注解时,还有一些要求:

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

下面我们就来自定义一个简单的注解:

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {String value();
}

那么注解的实质是什么呢?
我们把我们自定义的注解反编译一下,如下图所示:

public interface zzuli.edu.annotation.MyAnnotation extends java.lang.annotation.Annotation {public abstract java.lang.String value();
}

由反编译后的代码可知,注解的本质实际上是一个接口,并且该接口默认继承了 Annotation 接口。

5、JDK8中注解的新特性

Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。

  1. @Repeatable:可重复注解

当我们需要重复使用某个注解时,并且希望利用相同的注解来表现不同的形式时,我们可以借助@Repeatable注解。比如:我们在生活中一个人往往是具有多种身份,例如我是一家公司的员工,同时我还是我父母的孩子等等,此时我们就可以使用@Repeatable注解来完成。

在Java 8之前没有@Repeatable时,我们都是通过定义注解的数组来实现可重复注解的,如下所示:

//定义一个表示角色的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Role {String value();
}//定义一个角色数组的注解,表示可重复的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Roles {Role[] value();
}//使用表示可重复注解的Roles注解来表示人所扮演的不同的角色
@Roles({@Role("employee") ,@Role("son")})
public class People {}

在Java 8中出现了@Repeatable可重复注解之后,变得简单了很多。下面我们就来演示一下,还是使用上面的例子,方便我们进行对比。

//定义一个Role注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Roles.class) //表示Role注解是一个可重复注解
public @interface Role {String value();
}@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Roles {Role[] value();
}@Role("employee")
@Role("son")
public class People {}
  1. 类型注解

JDK1.8之后,关于元注解@Target的参数类型ElementType枚举值多了两个:TYPE_PARAMETER、TYPE_USE。
(1) ElementType.TYPE_PARAMETER:表示该注解能写在类型变量的声明语句中,如:参数声明、泛型声明等;
(2) ElementType.TYPE_USE:表示该注解能写在使用类型的任何语句中。

6、注解的底层实现原理

我们在使用框架时经常会使用注解,那注解底层到底是怎样执行的呢?下面我们通过一个例子来演示一下:

例子:自定义一个注解,注解标注在哪里就让哪个方法执行。

//自定义一个注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyJunit {}public class PrintNumber {public void showOdd(){  //打印奇数for (int i = 0; i < 10; i++) {if (i % 2!=0) {System.out.print(i+" ");}}}@MyJunitpublic void showEven(){ //打印偶数for (int i = 0; i < 10; i++) {if (i % 2==0) {System.out.print(i+" ");}}}
}public class JunitTest {public static void main(String[] args) throws Exception {//1.创建PrintNumber对象PrintNumber printNumber = new PrintNumber();//2.获取该类的字节码文件对象Class<? extends PrintNumber> clazz = printNumber.getClass();//3.获取对象中的所有方法Method[] methods = clazz.getMethods();for (Method method:methods) {//4.判断方法上是否有@MyJunit注解boolean flag = method.isAnnotationPresent(MyJunit.class);//5.如果方法上有@MyJunit注解,则执行if (flag){method.invoke(printNumber);}}}
}

运行结果:

由上述代码可知,注解底层是通过反射实现的。

易错点:由于注解默认的生命周期是在class文件中有效,当运行Java程序时, 注解就会失效。 所以我们在自定义注解时,要想在运行时使用,则应该把注解的生命周期设置为运行时有效(RetentionPolicy.RUNTIME),否则会报错。

天天用注解,你知道注解到底是怎样实现的吗?相关推荐

  1. spring框架注解多?注解到底是个什么东西?这篇文章给你讲明白

    目录 什么是注解 内置注解: 元注解: 自定义注解: 什么是注解 1.Annotation是从JDK5.0开始引入的新技术. Annotation的作用: 2.不是程序本身,可以对程序作出解释.(这一 ...

  2. java 反射 注解 运用_Java注解与反射的使用

    打开 Eclipse,新建 Java 项目"注解与反射",在 src 下右键并建立包 "注解与反射",在包下右键并建立 Annotation (注解)文件,名称 ...

  3. java注解机制_Java 注解机制

    一.注解中的信息已经在Class中了,我们应该如何读取出来 1 java.lang.reflect.AnnotatedElement接口:2 3 publicAnnotation[] getAnnot ...

  4. 注解和反射详细笔记。自定义注解,元注解,内置注解。反射机制,Java Reflection,Java内存分析,反射操作注解,java.lang.reflect.Method,Class

    文章目录 注解 什么是注解 内置注解 元注解 自定义注解 反射机制 静态语言 vs 静态语言 Java Reflection 反射相关的主要API Class类 Java内存分析 创建运行时类的对象 ...

  5. Java注解 编译_Java注解处理器学习之编译时处理的注解详析

    1. 一些基本概念 在开始之前,我们需要声明一件重要的事情是:我们不是在讨论在运行时通过反射机制运行处理的注解,而是在讨论在编译时处理的注解. 编译时注解跟运行时注解到底区别在什么地方?其实说大也不大 ...

  6. 理解Kotlin语言独有的位置注解,让注解控制更精准

    在Kotlin语言编写的代码中,你应该看到过类似这样的注解@file:JvmName(...),这有点难以理解,正常的注解不会存在类似@file:这样的前缀,在Java语言中也没有类似的语法.那么,这 ...

  7. @aspect注解类不生效_springboot:@Transactional注解 VS @Service注解

    1. Transactional注解与Service/Component注解冲突? 之前遇到一个神奇的事情--用Transactional注解的方法,数据处理了一半,后面的数据处理抛出异常后,没有回滚 ...

  8. 简述java中的注释以及用法_怎样理解 Java 注解和运用注解编程?

    正好最近在公众号(BetterAndroid)发了一篇关于注解的文章,贴在这里吧,希望对题主有帮助. 一.什么是注解 我们都知道在Java代码中使用注释是为了提升代码的可读性,也就是说,注释是给人看的 ...

  9. java 继承 注解_在java中实现组合注解原理分析(注解继承)

    今天在自定义注解的时候,原计划实现一个类似于Spring中的注解@Component的功能,如果稍有留意一下,会发现,在Spring中我们常见的注解,其实都继承了@Component注解:如下图所示: ...

  10. Java注解和xml_Spring注解配置和xml配置优缺点比较

    Spring注解配置和xml配置优缺点比较 编辑 ​ 在昨天发布的文章<spring boot基于注解方式配置datasource>一文中凯哥简单的对xml配置和注解配置进行了比较.然后朋 ...

最新文章

  1. Markdown基本语法使用
  2. 数据库获取的字符串按照逗号分隔,放进数组集合中
  3. 平时的鸿星尔克VS开挂后的鸿星尔克
  4. JQuery快速学一(强悍的选择器)
  5. 一文学会哈希法解题,助你事半功倍(leetcode哈希表面试高频题目总结)
  6. 查看EXE/DLL文件是32/64位之通用方法
  7. 百度换肤功能实现(vue)
  8. easyui combobox筛选(拼音)
  9. 2007年度全世界最好的50个网站
  10. Windows10中microsoft商店打不开解决办法
  11. 斐讯n1刷armbian建lnmp环境+WordPress
  12. CDH平台YARN日志查看和问题排查
  13. win7系统做网站服务器,win7系统做网站服务器
  14. swagger3 和knif4j
  15. python中end= 的含义
  16. MapINFO栅格图像载入方法
  17. 为什么说真理掌握在少数人手中
  18. Jenkins 集成蒲公英
  19. python3 poplib.POP3 连接超时问题
  20. 10-110 3-2-(d)查询在两种或两种以上PC机上出现的硬盘容量

热门文章

  1. html文本框的各种用法,HTML文本框5种应用方式实现方法
  2. 中国医药电商:这个江湖,有血有肉有侠义
  3. 智慧城市兴起,让我们看看智慧城市里面的3D可视化效果
  4. 【轴承故障分解】ITD轴承故障信号分解【含Matlab源码 1871期】
  5. pe启动自定义linux,详解PE启动自定义脚本
  6. DIR-815 路由器多次溢出漏洞分析
  7. linux 安装tar.gz软件
  8. inStream parameter is null
  9. 输出比较功能中的pwm以及其他功能的区分
  10. java socket接口文档_Java进阶 - 网络编程、Socket、函数式接口、常用的函数式接口...