目录
1.元注解
2.注解的声明
3.注解的使用
4.重复注解
java提供了一套java注解(Annotation)的机制,与java中的注释不同,注解是一种类型.通过使用注解,可以对方法,类,参数,包,域以及变量等添加标记(即附上某些信息),之后通过反射将标记的信息提取出来以供使用.
1.元注解
java.lang.annotation包提供了4种元注解,负责对注解类型进行约束,他们本身也实现了自注解.
@Target:表示该注解用于什么位置,可选的参数是ElementType枚举中的成员:
TYPE | 类型声明(类,接口,enum) |
FIELD | 成员变量声明(对象,属性,enum的实例) |
METHOD | 方法声明 |
PARAMETER | 参数声明 |
CONSTRUCTOR | 构造器声明 |
LOCAL_VARIABLE | 局部变量声明 |
ANNOTATION_TYPE | 注解声明 |
PACKAGE | 包声明 |
ElementType在SE1.8中又加入了两个成员:TYPE_PARAMETER,TYPE_USE.
@Retention:表示需要在什么级别保存该注解信息(生命周期),可选的参数是RetentionPolicy枚举中的成员:
SOURCE | 停留在java源文件,会将被编译器丢弃 |
CLASS | 停留在class文件中,但会被VM丢弃 |
RUNTIME | 内存中的字节码,VM在运行期间保留注解 |
注意,只有声明为RUNTIME,才可以通过反射机制读取注解的信息.
@Document:将注解包含在Javadoc中
@Inherited:允许子类继承父类中的注解,只针对CLASS级别的注解有效
2.注解的声明
语法:通过关键字@interface定义,默认继承Annotation接口.注解中通常会有一些元素(),用来表示一些值.这些元素看起来与接口中的方法相似,但是是无参的,并且可以通过default提供默认值,但默认值不能为null.注解中的元素只能是以下类型{所有基本类型,String,Class,Enum,Annotation(但不能是自己),以及以上类型的一维数组形式}.例:
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotateDemo {
int i();
float f() default 3.14f;
char[] c();
String[] s() default { "primitive type", "String", "Class", "annotation",
"enumeration", "arrays" };
Class<String> cls() default String.class;
Override ovr();
ElementType elmt();
}
注解可以不用元注解进行约束,也可以没有元素,没有元素的注解称为标记注解,例:
public @interface AnnotateDemo {
}
默认的ElementType可以是任意类型,RetentionPolicy是CLASS.
3.注解的使用
当我们定义了一个注解之后,便可以在允许的位置进行标记,标记时必须对注解内的元素进行赋值,有默认值的元素可以选择性赋值.如果注解只有一个元素且该元素的名称是value的话,在使用注解的时候可以省略"value="直接写需要的值即可.例:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotateDemo {
int i();
String s() default "hello";
}
public class AnnotateDemo3 {
@AnnotateDemo(i = 97)
public void a() {
}
@AnnotateDemo(i = 98, s = "world")
public void b() {
}
public void c() {
}
public void d() {
}
}
使用注解最主要的部分在于对注解的处理,那么就会涉及到注解处理器.注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理.在上述程序中加入:
public static void track(List<Integer> list, Class<?> cl) {
for (Method m : cl.getDeclaredMethods()) {
AnnotateDemo ant = m.getAnnotation(AnnotateDemo.class);
if (ant != null) {
System.out.println("Found:" + ant.i() + "_" + ant.s());
list.remove(new Integer(ant.i()));
}
}
for (int value : list) {
System.out.println("notFound:" + value);
}
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 97, 98, 99, 100);
track(list, AnnotateDemo3.class);
}
静态方法track需要List和Class的参数,遍历cl中的方法,通过getAnnotation()方法,判断cl中的方法是否被标记.如果是,则输出注解的详细信息,然后在list中remove掉对应的值,最后再输出list中剩下的值.输出结果:
Found:97_hello
Found:98_world
notFound:99
notFound:100
这也是一个简单的跟踪项目中的例子.
4.重复注解
SE1.8引入了重复注解的特性,允许在声明同一类型时使用多次同一个注解,提高了程序的可读性,例:
import java.lang.annotation.Repeatable;
@Repeatable(AnnotateDemoFactory.class)
@interface AnnotateDemo {
String s();
}
@interface AnnotateDemoFactory {
AnnotateDemo[] value();
}
public class AnnotateDemo4 {
@AnnotateDemo(s = "hello")
@AnnotateDemo(s = "world")
public void a() {
}
}
通过使用另一个注解来存储重复注解,创建重复注解AnnotateDemo时,加上@Repeatable,指向存储注解AnnotateDemoFactory.在使用时可以重复使用AnnotateDemo来进行标记.
小结:了解java中注解的用法需要对反射有一定了解,通过使用注解可以实现生成文档,编译检查等功能,同时增加了程序的可读性.