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个非常重要的主干类。它们分别是:
- Annotation.java
- ElementType.java
- 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/
上一篇: PHP实现图片旋转效果实例代码,