Java中的注解、元注解详细解析
作者:四叶草
1.注解概述
- JDK5.0新增 — 注解(Annotation),也叫元数据。与类、接口、枚举是在同一个层次,它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
- Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中。在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/ArIdroid中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。未来的开发模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以后都是基于注解的,Hibernate3.x以后也是基于注解的,注解是一种趋势,一定程度上可以说 :框架=注解+反射+设计模式。
2.注解分类
作用分类:
- 编写文档: 通过代码里标识的元数据生成文档【生成文档doc文档】
- 代码分析: 通过代码里标识的元数据对代码进行分析【使用反射】
- 编译检查: 通过代码里标识的元数据让编译器能够实现基本的编译检查【Override等】
注解可以根据注解参数分为三大类:
- 标记注解: 没有参数的注解,仅用自身的存在与否为程序提供信息,如@Override注解,该注解没有参数,用于表示当前方法为重写方法。
- 单值注解: 只有一个参数的注解,如果该参数的名字为value,那么可以省略参数名,如 @SuppressWarnings(value = “all”),可以简写为@SuppressWarnings(“all”)。
- 完整注解: 有多个参数的注解。
3.三种基本的Annotaton
3.1**@Override**
- 限定某个方法,是重写父类方法 , 该注解只能用于方法
- 在子类中去实现父类的方法,就会在方法上有@Override注解,假如我们试图去重写eat方法名称,会发现在编译期就报错了,就说明该方法不是我们重写其父类(eat)的方法
3.2**@Deprecated**
- 用于表示某个程序元素 ( 类 , 方法等,字段, 包, 参数 ) 已过时
- 已过时不是不能使用,只是不推荐使用,但是仍然可以使用
3.3**@SuppressWarnings**
- 关于 SuppressWarnings 作用范围是和你放置的位置相关。比如@SuppressWarnings 放置在 main 方法,那么抑制警告的范围就是 main
- 通过 @SuppressWarnings 的源码可知,其注解目标为类、字段、函数、函数入参、构造函数和函数的局部变量。
- @SuppressWarnings在IDEA中不明显,在eclipse中有显示黄色警告。
unchecked:未检查的转化,如集合没有指定类型还添加元素
unused:未使用的变量
resource:有泛型未指定类型
path:在类路径,原文件路径中有不存在的路径
deprecation:使用了某些不赞成使用的类和方法
fallthrough:switch语句执行到底没有break关键字
rawtypes:没有写泛型,比如: List list = new ArrayList();
all:全部类型的警告
4.元注解(重点)
- 元注解是用于修饰其它注解的注解
四种元注解:
- @Documented:指定了被修饰的注解是可以Javadoc等工具文档化
- @Retention:指定了被修饰的注解的生命周期
- @Target:指定被修饰的注解的作用范围
- @Inherited:指定了被修饰的注解修饰程序元素的时候是可以被子类继承的
4.1**@Documented**
- 用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了。
- 定义为@Documented 的注解必须设置Retention值为RUNTIME。
4.2@Retention
只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间,@Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值(值有三种)。
三种值:
- RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释。
- RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中 . 当运行 Java 程序时 , JVM 不会保留注解。 这是默认值。
- RetentionPolicy.RUNTIME: 编译器将把注解记录在 class 文件中 . 当运行 Java 程序时 , JVM 会保留注解 . 程序可以 通过反射获取该注解。
注意: 我们常用的定义即是RetentionPolicy.RUNTIME,因为我们使用反射来实现的时候是需要从JVM中获取class类对象并操作类对象的。
三个生命周期是 源码阶段 - > class类对象阶段 - > Runtime运行时阶段。
4.3**@Target**
用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素。@Target也包含一个名为value的成员变量。
ANNOTATION_TYPE 用于描述注解
CONSTRUCTOR 用于描述构造方法
FIELD 用于描述属性
LOCAL_VARIABLE 用于描述局部变量
METHOD 用于描述方法
PACKAGE 用于描述包
PARAMETER 用于描述方法内的参数
TYPE 用于描述类型进行注解,比如类、接口、枚举
4.4**@Inherited**
被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
5.自定义注解
格式:public @Interface 注解名 {
属性列表/无属性
}
注解体中的属性要求(返回值类型):
1、基本数据类型
2、String类型
3、枚举类型
4、注解
5、以上类型的数组
注解的属性也叫做成员变量。注解只有成员变量,没有方法。
注意:
- 在这里不能有void的无返回值类型和以上类型以外的类型
- 定义的属性,在使用时需要给注解中的属性赋值
- 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不为属性赋值,它取的是默认值。如果为它再次传入值,那么就发生了对原值的覆盖。
- 如果只有一个属性需要赋值,并且属性的名称为value,则赋值时value可以省略,可以直接定义值
- 数组赋值时,值使用{}存储值。如果数组中只有一个值,则可以省略{ }
6.注解的提取
注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
然后通过 getAnnotation() 方法来获取 Annotation 对象,或者是 getAnnotations() 方法。。
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {} public Annotation[] getAnnotations() {} //前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。
如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { public int id() default -1; public String msg() default "Hi"; } //TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi
//因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略 @TestAnnotation() public class Test { public static void main(String[] args) { boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class); if ( hasAnnotation ) { TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class); System.out.println("id:"+testAnnotation.id()); System.out.println("msg:"+testAnnotation.msg()); } } }
到此这篇关于Java中的注解、元注解详细解析的文章就介绍到这了,更多相关Java中的注解、元注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!