Java中的Annotation (一、系统内建的Annotatiion)
对于Annotation,是Java5以来的新特性,JDK5引入了Metadata(元数据)。所谓元数据就是关于数据的数据。注解就是代码的元数据,他们包含了代码自身的信息。注解可以被用在包,类,方法,变量,参数上。 Java中的Annotation就是一种元数据,它提供一些本来不属于程序的数据,比如:一段代码的作者或者告诉编译器禁止一些特殊的错误。被注解的代码并不会直接被注解影响。这只会向第三系统提供关于自己的信息以用于不同的需求。注解会被编译至class文件中,而且会在运行时被处理程序提取出来用于业务逻辑。当然,创建在运行时不可用的注解也是可能的,甚至可以创建只在源文件中可用,在编译时不可用的注解。
Annotation一般作为一种辅助途径,应用在软件框架或工具中,在这些工具类中根据不同的annontation注解信息采取不同的处理过程或改变相应程序元素(类、方法及成员变量等)的行为。
Annotation注解可以满足许多要求,最普遍的是:
- 向编译器提供信息:注解可以被编译器用来根据不同的规则产生警告,甚至错误。一个例子是Java8中@FunctionalInterface注解,这个注解使得编译器校验被注解的类,检查它是否是一个正确的函数式接口。
- 文档:注解可以被软件应用程序计算代码的质量例如:FindBugs,PMD或者自动生成报告,例如:用来Jenkins, Jira,Teamcity。
- 代码生成:注解可以使用代码中展现的元数据信息来自动生成代码或者XML文件,一个不错的例子是JAXB。
- 运行时处理:在运行时检查的注解可以用做不同的目的,像单元测试(JUnit),依赖注入(Spring),校验,日志(Log4j),数据访问(Hibernate)等等。
Annotation的核心的工作原理就是借助一个操作类通过反射的方式提取Annotation信息,进行操作。由此可见反射机制在java中用途广泛。
声明一个注解需要使用“@”作为前缀,这便向编译器说明,该元素为注解。
系统内建的 Annotation(元注解)
主要有以下几种:
@Override // 声明某一个方法是用于覆盖父类中的方法,如果不是,就会在编译时报错
@Deprecated //声明某一个方法 ,某一个类,不建议使用。已经过时。
@SuppressWarnings //压制一些警告,比如泛型uncheck ,方法unuse
@Documented //被注解的元素将会作为Javadoc产生的文档中的内容。注解都默认不会成为成为文档中的内容。这个注解可以对其它注解使用。
@Inherited //在默认情况下,注解不会被子类继承。被此注解标记的注解会被所有子类继承。@Inheriated注解仅在存在继承关系的类上产生效果,在接口和实现类上并不工作。这条同样也适用在方 法,变量,包等等。只有类才和这个注解连用。
@Retention:这个注解注在其他注解上,并用来说明如何存储已被标记的注解。这是一种元注解,用来标记注解并提供注解的信息。可能的值是:
- SOURCE 表明这个注解会被编译器忽略,并只会保留在源代码中。
- CLASS: 表明这个注解会通过编译驻留在CLASS文件,但会被JVM在运行时忽略,正因为如此,其在运行时不可见。
- RUNTIME 表示这个注解会被JVM获取,并在运行时通过反射获取。
@Target:这个注解用于限制某个元素可以被注解的类型。例如:
- ANNOTATION_TYPE 表示该注解可以应用到其他注解上
- CONSTRUCTOR 表示可以使用到构造器上
- FIELD 表示可以使用到域或属性上
- LOCAL_VARIABLE 表示可以使用到局部变量上。
- METHOD 可以使用到方法级别的注解上。
- PACKAGE 可以使用到包声明上。
- PARAMETER 可以使用到方法的参数上
- TYPE 可以使用到一个类的任何元素上。
下面请看关于前三种注解的demo
1、@Override
覆盖父类接口中未实现的抽象方法。
package com.iip; interface Demo{ String getInfo(); } class Child implements Demo{ @Override //覆盖父类中的方法 public String getInfo(){ return "child"; } } public class AnnotationDemo { public static void main(String[] args) { // TODO Auto-generated method stub Child d = new Child(); System.out.println(d.getInfo()); } }
2、@Deprecated
直接在上面代码中@Override下面加入一行@Deprecated
class Child implements Demo{ @Override @Deprecated public String getInfo(){ return "child"; } }
通过javac编译就会发现
提醒你使用了过时的API。
注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译。
加入 -Xlint:deprecation 后再次编译
便提示了详细信息。
3、@SuppressWarnings
还是在上述代码中,在main函数上面加入@SuppressWarnings("deprecation")
@SuppressWarnings("deprecation") public static void main(String[] args) { // TODO Auto-generated method stub Child d = new Child(); System.out.println(d.getInfo()); }
再次编译将不会出现警告
或者也可以这样写 @SuppressWarnings(value={"deprecation"})
value接收的是一个数组,你可以加入多个参数,比如@SuppressWarnings(value={"deprecation","unchecked"})
@SuppressWarnings需要加入参数,这些参数都是已经定义好的了,定义的参数有如下几个。
deprecation 使用了过时的类或方法时的警告
unuse 定义的方法没用使用的警告
unchecked 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型
fallthrough 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告
path 在类路径、源文件路径等中有不存在的路径时的警告
serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告
finally 任何 finally 子句不能正常完成时的警告
all 关于以上所有情况的警告
明天将会继续学习如何构造自定义的Annotation。