Java注解学习笔记

标签: Java注解  注解

什么是注解

注解(Annotation)是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符,它是一种由JSR-175标准选择用来描述元数据的一种工具。Java从Java5开始引入了注解。在注解出现之前,程序的元数据只是通过java注释和javadoc,但是注解提供的功能要远远超过这些。注解不仅包含了元数据,它还可以作用于程序运行过程中、注解解释器可以通过注解决定程序的执行顺序。

比如,下面这段代码:

@Override
public String toString() { 
    return "This is String.";
}

上面的代码中,我重写了toString()方法并使用了@Override注解。但是,即使我们不使用@Override注解标记代码,程序也能够正常执行。那么,该注解表示什么?这么写有什么好处吗?事实上,@Override告诉编译器这个方法是一个重写方法(描述方法的元数据),如果父类中不存在该方法,编译器便会报错,提示该方法没有重写父类中的方法。如果我不小心拼写错误,例如将toString()写成了t0String(),而且我也没有使用@Override注解,那程序依然能编译运行。但运行结果会和我期望的大不相同。现在我们了解了什么是注解,并且使用注解有助于阅读程序。

为什么要引入注解

在引入注解之前,基本都是用XML来描述元数据。

但是后来发现XML越写越多,而且原来越难维护。

注解的出现是为了解决XML的弊端。

注解的架构

先看看Annotation的架构图:

从中,我们可以看出:

  • 1个Annotation 和 1个RetentionPolicy关联。可以理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性。
  • 1个Annotation 和 n个ElementType关联。可以理解为:对于每1个Annotation对象,可以有若干个ElementType属性。
  • Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override等等。
  • Annotation 的每一个实现类,都“和1个RetentionPolicy关联”并且“和n个ElementType关联”。

Java注解分类

元注解

基本注解

注解(Annotation)组成部分

Annotation组成成分

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

  1. Annotation.java
  2. ElementType.java
  3. RetentionPolicy.java

Annotation.java

public interface Annotation {
    boolean equals(Object obj);
    int hashCode();
    String toString();
    Class<? extends Annotation> annotationType();
}
  • Annotation 是个接口
  • 有四个函数

ElementType.java

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

ElementType 是Enum枚举类型,它用来指定Annotation的类型。

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

RetentionPolicy.java

public enum RetentionPolicy {
    SOURCE,    // 只保留在源代码中,编译器编译时,直接丢弃这种注解,不记录在.class文件中
    CLASS,    // 编译器把注解记录在class文件中。当运行Java程序时,JVM中不可获取该注解信息,这是默认值
    RUNTIME    // 编译器把注解记录在class文件中。当运行Java程序时,JVM可获取该注解信息。程序可以通过反射获取该注解的信息
}

RetentionPolicy 是Enum枚举类型,它用来指定Annotation的策略。

通俗点说,就是不同RetentionPolicy类型的Annotation的作用域不同

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

  • SOURCE:只保留在源代码中,编译器编译时,直接丢弃这种注解,不记录在.class文件中。
  • CLASS:编译器把注解记录在class文件中。当运行Java程序时,JVM中不可获取该注解信息,这是默认值。
  • RUNTIME:编译器把注解记录在class文件中。当运行Java程序时,JVM可获取该注解信息。程序可以通过反射获取该注解的信息。

源码分析

通用注解定义

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
}

@interface

@interface并不属于注解,而是定义注解的关键字。所以这里单独分析

     使用@interface定义注解时,意味着它实现了java.lang.annotation.Annotation接口,即该注解就是一个Annotation。
     定义Annotation时,@interface是必须的。
     注意:它和我们通常的implemented实现接口的方法不同。Annotation接口的实现细节都由编译器完成。通过@interface定义注解后,该注解不能继承其他的注解或接口。

元注解

元注解的意思就是注解的注解

注解

说明

@Documented

@Documented 所标注内容,可以出现在Javadoc中。

@Target

@Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。

@Retention

@Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。

@Inherited

@Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。

@Documented

源代码

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

作用:如果使用@Documented修饰该Annotation,则表示它可以出现在Javadoc中。

 定义Annotation时,@Documented可有可无;若没有,则Annotation不会出现在Javadoc中。

@Target(ElementType.TYPE)

源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * 返回一个数组,这个数组里的元素表明了哪些类型可以被注解
     */
    ElementType[] value();
}

作用:规定了该注解能作用在哪些地方

  • 若有@Target,则该Annotation只能用于它所指定的地方
  • 若没有@Target,则该Annotation可以用于任何地方。

ElementType的取值有

  • TYPE:类、接口(包括注释类型)或枚举
  • FIELD:字段(包括枚举常量)
  • METHOD:方法
  • PARAMETER:参数
  • CONSTRUCTOR:构造方法
  • LOCAL_VARIABLE:局部变量
  • ANNOTATION_TYPE:注释类型
  • PACKAGE:包

@Retention(RetentionPolicy.Policy)

源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * 返回一个RetentionPolicy
     */
    RetentionPolicy value();
}

作用:在哪种级别保存该注解信息。
定义Annotation时,@Retention可有可无。

若没有@Retention,则默认是RetentionPolicy.CLASS。

@Retention 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

  • SOURCE:只保留在源代码中,编译器编译时,直接丢弃这种注解,不记录在.class文件中。
  • CLASS:编译器把注解记录在class文件中。当运行Java程序时,JVM中不可获取该注解信息,这是默认值。
  • RUNTIME:编译器把注解记录在class文件中。当运行Java程序时,JVM可获取该注解信息。程序可以通过反射获取该注解的信息。

Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

@Inherited

源码

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

@Inherited指定注解具有继承性。如果某个类使用了@xxx注解(定义该注解时使用了@Inherited修饰)修饰,则其子类将自动被@xxx修饰。

基本注解

注解

说明

@Override

@Override 只能标注方法,表示该方法覆盖父类中的方法。

@Deprecated

@Deprecated 所标注内容,不再被建议使用。

@SuppressWarnings

@SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。

通过上面的示例,我们能理解:@interface用来声明Annotation,@Documented用来表示该Annotation是否会出现在javadoc中, @Target用来指定Annotation的类型,@Retention用来指定Annotation的策略。

@Override

源码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
  • @interface:意味着Override实现了java.lang.annotation.Annotation接口;即Override就是一个注解。
  • @Target(ElementType.METHOD) :@Override只能作用于方法,不能作用于其他。
  • @Retention(RetentionPolicy.SOURCE):@Override只保留在源代码中,编译器编译时,直接丢弃这种注解,不记录在.class文件中。

@Override用于标注重写了父类的方法。对于子类中被@Override修饰的方法,如果存在对应的被重写的父类方法,则正确;如果不存在,则报错。@Override只能作用于方法,不能作用于其他程序元素。

阿里开发手册里规定所有覆盖写方法,必须加上@Override

(四) OOP规约

2. 【强制】所有的覆写方法,必须加@Override注解。 说明:getObject()与get0bject()的问题。一个是字母的O,一个是数字的0,加@Override可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错。

@Deprecated

@Deprecated 的定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

说明:

  • @interface:意味着Deprecated实现了java.lang.annotation.Annotation接口;即Deprecated就是一个注解。
  • @Documented:说明该注解能出现在Javadoc中。
  • @Retention(RetentionPolicy.RUNTIME):编译器把Deprecated记录在class文件中。当运行Java程序时,JVM可获取该注解信息。程序可以通过反射获取该注解的信息。

作用:

@Deprecated 所标注内容,不再被建议使用。
     例如,若某个方法被 @Deprecated 标注,则该方法不再被建议使用。如果有开发人员试图使用或重写被@Deprecated标示的方法,编译器会给相应的提示信息。示例如下:

@SuppressWarnings

源码

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

说明:

  • @interface:意味着SuppressWarnings实现了java.lang.annotation.Annotation接口;即SuppressWarnings就是一个注解。
  • @Retention(RetentionPolicy.SOURCE):规定了SuppressWarnings信息仅存在于编译器处理期间,编译器处理完之后SuppressWarnings就没有作用了。
  • @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}):指定SuppressWarnings的类型同时包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE。
  • String[] value():SuppressWarnings能指定参数

作用:

SuppressWarnings 的作用是让IDE对指定的Warnings进行忽略。

例如,"@SuppressWarnings(value="deprecation")" 说明忽略对“不建议使用”这个提醒进行忽略。

补充:SuppressWarnings 常用的关键字的表格

关键字

说明

deprecation

使用了不赞成使用的类或方法时的警告

unchecked

执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。

fallthrough

当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。

path

在类路径、源文件路径等中有不存在的路径时的警告。

serial

当在可序列化的类上缺少 serialVersionUID 定义时的警告。

finally

任何 finally 子句不能正常完成时的警告。

all

关于以上所有情况的警告。

参考:

http://blinkfox.com/javazhu-jie-de-li-jie-he-ying-yong/

http://wangkuiwu.github.io/2012/03/03/annotation/

 

版权声明:本文为CrankZ原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/CrankZ/article/details/81944621

智能推荐

FFMPEG完美入门资料---002---FFmpeg 支持能力说明

接着上文写: 2.3.1 FFmpeg 对编码解码器的支持 ffmpeg 支持的编解码器种类共有 280 多种, 涵盖了几乎所有常见音视频编码格式, 能解码几乎所有的音视频, 每种音视频编解码器的实现都在 libavcodec 目录下有具体的 C 语言实现。 * 注:编码器和解码器的名称不是完全匹配的,因此有些编码器没有对应相同名称的解码器,反之, 解码器也一样。即使编码和解码都支持也不一定是完全...

20145107 《Java程序设计》第五次实验报告

实验简述: 在本周,我们进行了Java的第五次试验,本次实验的主要内容是结对编程。本次实验的大体过程是: 1.先进行Java的客户端与服务端的代码编写。结对是两个人,一人负责客户端,一人负责服务端。 2.利用加解密代码包,编译运行代码,客户端加密,服务器解密。 3.客户端加密明文后将密文通过TCP发送。 4.在本次的代码编写上,要求代码可以实现两者之间的数据传输,在代码传输的基础上加上一定的加密过...

更改springboot启动拼成的字母

1.更改springboot启动拼成的字母 其实很好改,只需要在resources下新建一个txt文件就可以,命名为banner.txt,那这种字符该怎么拼出来呢,下面推荐一个网址,有这种工具 传送门 2.集成...

Node.js安装配置

好久都没更新博客了,今天心血来潮,决定是时候更新一篇了,首先我们来认识一下node.js。 什么是node.js? 简单的说 Node.js 就是运行在服务端的 JavaScript。 Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的...

RocketMQ之双Master集群搭建笔记记录

一:RocketMQ双master集群部署 服务器环境(我采用的虚拟机,centos6 .5【特别注意:安装的虚拟机centos系统一定得是64位的,32位的会启动不起来。即便起来了也会有很多问题,深坑勿踩】)  ip       用户名    密码        角色     模式 192.168.197.101   root        nameServer1,brokerServer1  ...

猜你喜欢

蓝桥杯试题集-基础练习题-数列特征(Java)

//做题笔记,仅自己看得懂 题目: 正确姿势:...

多线程爬取4k超高清美图壁纸

多线程爬取4k美图壁纸 前言:看完此篇文章你可以更加深入的了解多线程的使用,并且最重要的你能够下载你自己想要的超高清4k壁纸 爬取结果: 1. 分析网站 要爬取的url :http://pic.netbian.com/ a) 判断网页是动态加载还是静态加载页面。右击查看网页源代码,按Ctrl + f在源代码中搜索网站的详情页地址,从而判断整个网页是静态加载的 b) 明确爬取的目标。我们要爬取的目标...

elementUI-添加自定义图标

elementui的小图标有限,跟UI给的不一样,这个时候咋办呢?百度走起。。。。参考了两篇博主分享的 自定义elementui中的图标 和 建立图标库,这里主要用到第一种 实际中: elementUI导航栏 具体代码: 汉字转换Unicode编码: 直接打开控制台: 汉字.chatCodeAt().toString(16); 然后回车; 至于三角形的图标,我直接把箭头的 unicode 值改成了...

[Linux]——文件缓冲区

文件缓冲区 提到文件缓冲区这个概念我们好像并不陌生,但是我们对于这个概念好像又是模糊的存在脑海中,之间我们在介绍c语言文件操作已经简单的提过这个概念,今天我们不妨深入理解什么是文件缓冲区。 为什么需要文件缓冲区 当我们在程序中写下一条printf语句时,我们希望将这条语句的内容打印到屏幕上。但是如果你将语句放在循环中,难道你执行一次循环那么操作系统就要打印一次这条数据么?答案当然不是 我们对于程序...

基于FPGA的IIC协议详解——EEPROM控制器(1)

IIC协议举例 常用IIC协议使用地方 常见IIC协议的注意点 24LC64芯片读写命令的时序图 eeprom控制器的系统框图 时序图设计 代码设计 EEPROM控制器测试模块的代码 结束语 常用IIC协议使用地方 熟悉一个协议一定要知道这个协议应该用到什么地方,IIC协议作为飞利浦公司定义的一个慢速传输协议,常用于: 1、芯片寄存器的配置; 2、eeprom的读写; 本次实验我们将使用eepro...