6. Java语言内置的Annotation简介
6.1 基本内置类型
在Java 1.5 之后,引入了三个基本的Annotation类型,分别为: @Override,@Deprecated, @SuppressWarnings.
- @Override
java.lang.Override,作用于方法级别,只存在与编译阶段使用,由于其定义涵盖@Target(value=METHOD), @Retention(value=SOURCE)。
其为Marker Annotation, 仅用作标识方法,表示其重载了父类的方法;如果使用了@Override,实际上却并未覆盖父类方法,java编译器将提示一个编译错误。我们其实,可以将其理解为一个强化语法检查的断言,辅助开发者减少错误。
2. @Deprecated标识Annotation,作用于方法各个级别的代码,在运行阶段使用。
在使用@Deprecated修饰的方法、变量等之后,编译器将不鼓励使用这个被标注的程序元素。使用这种修饰可以扩散到子类中,例如在代码中通过继承或者覆盖的方式使用了这个@Deprecated标识的类型或者成员,即使继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要抛出警告信息。
在代码中,适用于所有代码级别,Retention适用于源代码级别(Source),用以提示Java编译器Java编译器关闭对类、方法及成员变量的警告。对于代码中不希望反复看到的警告信息,可以通过这个注解来屏蔽,编译器将不再抛出警告。
与之前的两个Annotation不同,@SuppressWarnings可以使用响应的成员变量,从而可以更精细化的控制提示警告信息的出现。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
其内部可以基于String[],传入需要屏蔽的警告类型信息。使用示例如下:
@SuppressWarnings(value={"unchecked","fallthrough"})
public void suppressedMethod() {
//Logic Code
}
这里仅仅列出了两种需要屏蔽的警告类型,如需查看所有可能的警告信息类型,可以查看参考资料4.
6.2 Meta-Annotation
主要功能是用以修饰Annotation,简而言之,就是用以创建新的Annotation的修饰Annotation。虽然有点绕口,Meta-Annotation就明确地表明他的位置。先看一个例子吧:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }这个是Target在JDK源码中的定义,通过这个例子充分说明了Meta-Annotation的用法。 这里比较有意思的是,@Target在源码中是通过自我定义来完成的,就是@Target本身是使用@Target来修饰和定义的。
这个例子中@Documented标识其会在javadoc中出现,@Retention标识其在代码运行中使用,@Target标识其仅用作Annotation类型。
接下来,我们将分别对这些Meta-Annotation做详细讲解。
- @Target
限定Annotation所修饰的对象范围,范围包括packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标,一句话,这个Annotation可以用在什么地方。
可用的取值(ElementType)有:
- CONSTRUCTOR:用于描述构造器
- FIELD: 用于描述域
- LOCAL_VARIABLE: 用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型) 或enum声明
2. @Rentention
定义了该Annotation被保留的时间长短,或者说生命周期,即其会在哪个阶段被保留,并在哪个阶段会被使用到。
其value的取值(RetentionPoicy)有:
- SOURCE:在源文件中有效(即源文件保留)
出现在源代码中,而被编译器丢弃。
- CLASS:在class文件中有效(即class保留)
被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略。
- RUNTIME:在运行时有效(即运行时保留)
其被编译到class中,并在运行时,被读取和使用的。
3. @Documented
描述其它类型的annotation被作为被标注的程序成员的公共API,从而被javadoc此类的工具文档化。标记注解,没有成员。
4. @Inherited
标记注解,标识某个被标注的类型是被继承的。使用了@Inherited修饰的annotation类型被用于一个class之时,,则这个annotation将被用于该class的相应子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
就是说, 查看查找@Inherited过的Annotation之时,需要反复的向上查找,方才可以。
下面以Spring中@Controller的定义为样例来看看它们的使用:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { }
@Target中ElementType.Type标识其用于类或借口,Rention标识运行中,@Documented标识其已经在Javadoc中标识出来。 @Component是Spring中自定义的一个Annotation,标识其可以被IOC容器自动探测到。
限于篇幅,这里就不再针对@Inherited做示例讲解了,大家如果感兴趣的话,可以查看以下链接中的示例,就一目了然了。
范例讲解: http://www.jroller.com/alessiopace/entry/annotation_inheritance_examples
总结: 在本节中,我们着重讲解了Java语言中内置的Annotation和Meta-Annotation。