一、深入理解注解Annotation
要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。
二、Java SE5内置的三种注解
@override:表示当前定义的方法将覆盖超类中的方法,如果方法名写错,编译器就会报错。
@Deprecated :如果程序员使用了该注解,那么编译器会发出警告信息。
@SuppressWarnings:关闭不当的编译器警告信息,在Java SE5之前可以使用该注解,但是不起作用。
三、Java提供的元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其
它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。
@Target:表示该注解可用于什么地方。可能的ElementType参数如下:
1.CONSTRUCTOR:构造器的声明
2.FIELD:域声明(包括enum实例)
3.LOCAL_VARIABLE:局部变量声明
4.METHOD:方法声明
5.PACKAGE:包声明
6.PARAMETER:参数声明
7.TYPE:类、接口(包括注解类型) 或enum声明
@Retention:需要在什么级别保存该注解信息:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)(注解将被编译器丢弃)
2.CLASS:在class文件中有效(即class保留)(注解在class文件中可用,但会被jvm丢弃)
3.RUNTIME:在运行时有效(即运行时保留)(jvm在运行期保留注解,因此可以通过反射机制读取信息)
Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。
@Documented:将此注解包含在javadoc中。Documented是一个标记注解,没有成员。
@Inherited:允许子类继承父类中的注解。@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类型被发现,或者到达类继承结构的顶层。
四、自定义注解案例分析
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
}
注意:id和description的定义和方法的定义类似,由于编译器会对id进行类型检查,将用例文档的追踪数据库与源代码相关联是可靠的。description 有一个default的默认值,如果在注解时没有给出description的值,那么注解的处理器就会使用此元素的默认该值 no description。
package org.wangkeqing.annotation;
import java.util.List;
public class PasswordUtils {
@UseCase(id=47,description="Passwords must contain at least one numeric")
public boolean validatePassword(String password){
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id=48)
public String encriptPassword(String password){
return new StringBuilder(password).reverse().toString();
}
@UseCase(id=49,description="New Password can't equal previously used ones")
public boolean checkForNewPassword(List<String> prevPasswords,String password){
return !prevPasswords.contains(password);
}
}
如上,在encryptPassword方法中,没有出现description的值,此时注解处理器description的值就是默认值。