欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java注解学习笔记

程序员文章站 2022-03-31 21:17:36
...

什么是注解

注解(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的弊端。

注解的架构

Java注解学习笔记

先看看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可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错。

Java注解学习笔记

@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标示的方法,编译器会给相应的提示信息。示例如下:

Java注解学习笔记

@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")" 说明忽略对“不建议使用”这个提醒进行忽略。

Java注解学习笔记

补充: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/

 

相关标签: Java注解 注解