1.基本的Annotation:
a) @Override:限定重写父类的方法(只能用于方法,不能用于其他元素)
b) @Deprecated:标示已经过时
c) @SurpressWarnings:抑制编译器警告: @SuppressWarnings("unused")
d) @SafeVarargs:泛型擦除时,当把一个不带泛型的对象赋给一个带泛型的变量时,往往就会发生“堆污染”
List list=new ArrayList<>();
list.add(20);
List<String> list2=list;
System.out.println(list2.get(0));//运行时程序会报错,发生类型转换异常
2.JDK的元Annotation:元Annotation用于修饰其他的Annotation定义
a) 使用@Retention:用于修饰指定的Annotation可以保留多长时间
i. RetentionPolicy值:
1. RetentionPolicy.CLASS:默认值,编译器把Annotation记录在class文件中。当运行java程序时,JVM不再保留Annotation;
2. RetentionPolicy.RUNTIME:编译器把Annotation记录在class文件中,当运行java程序时,JVM保留Annotation;
//保留到运行时
@Retention(value=RetentionPolicy.RUNTIME)
public @interface RetentionTest{}
3. RetentionPolicy.SOURCE:Annotation只留在源代码中,编译器直接丢弃这种Annotation。
//将被编译器直接丢弃
@Retention(RetentionPolicy.SOURCE)
public @interface RetentionTest{}
ii. 如果Annotation中只有一个value成员变量,那么使用该Annotation时可以直接在其后面的括号里指定成员value的值,无须使用name=value的形式。
b) 使用@Target:用于指定被修饰的Annotation只能修饰哪些程序单元。
i. ElementType值:
1. ElementType.ANNOTATION_TYPE:用于指定该策略的Annotation只能修饰Annotation;
2. ElementType.CONSTRUCTOR:用于指定该策略的Annotation只能修饰构造器;
3. ElementType.FIELD:用于指定该策略的Annotation只能修饰成员变量;
4. ElementType.LOCAL_VARIABLE:指定策略的Annotation只能修饰局部变量;
5. ElementType.METHOD:用于指定该策略的Annotation只能修饰方法定义;
6. ElementType.PACKAGE:用于指定该策略的Annotation只能修饰包定义;
7. ElementType.PARAMETER:用于指定该策略的Annotation只能修饰参数;
8. ElementType.TYPE:指定该策略Annotation可以修饰类、接口、或者枚举定义。
@Target(ElementType.METHOD)
public @interface RetentionTest{}
c) 使用Documented:用于指定该元Annotation修饰的Annotation类将被javadoc工具提取成文档。
@Documented
public @interface RetentionTest{}
d) 使用@Inherited:指定被他修饰的Annotation将具有继承性---如果某个类使用了@A Annotation(定义该Annotation时使用了@Inherited修饰)修饰,则其子类将会自动被@A修饰;
可以用:XXX.class.isAnnotationPresent(A.class) 来判断一个类是否有RetentionTest的修饰。
3.使用自定义的Annotation:
a) 定义Annotation:使用 @interface 关键字:
public @interface Mytag
b) 定义Annotation成员变量:以无形参的方法形式来声明,其方法和返回值定义了该成员变量的名字和类型:
{
String name();
int age();
}
@Mytag(name="ss",age=3)//使用带成员变量的Annotation时需要为成员变量赋值
public void info(){}
c) 也可以为Annotation的成员变量指定默认值,这样在使用时,如果不为成员变量指定值,则使用默认值
{
String name() default "ss";
int age() default 2;
}
d) 根据Annotation是否含有成员变量把其分为两类:
i. 标记Annotation:一个没有定义成员变量的Annotation类型被称为标记,这种Annotation仅利用自身的存在与否来为我们提供信息,比如@Override
ii. 元数据Annotation:包含成员比那里的Annotation,因为他们可以接受更多的元数据,所以也被称为元数据Annotation。
4.提取Annotation信息:
a) java5之后新增了AnnotatedElement接口,该接口可以接受注释的程序元素。
i. 几个实现类:
1. Class:类定义
2. Constructor:构造器定义
3. Field:类的成员变量定义
4. Method:类的方法定义
5. Package:类的包定义
当一个Annotation类型被定义为运行时Annotation之后,该Annotation才会在运行时可见,JVM才会在转载*.class文件的时候读取保存在class中的Annotation;
b) 程序通过反射获取到某个类的AnnotatedElement对象之后,程序就可以调用下面方法获取到想要的信息:
i. getAnnotation(Class<T> annotationClass):返回该程序元素上存在的指定类型的注释,如果该类型的注释不存在,则返回null;
ii. Annotation[] getAnnotations():返回该程序元素上存在的所有注释;
Annotation[] annotations = Class.forName("com.gu.test.ch14.MytagTest").getMethod("info").getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation);}
iii. boolean isAnnotationPresent(Class <? extends Annotation > annotationClass):判断程序上是否存在指定的注释。
c) 获取某个Annotation里面的元数据:
MytagTest mytagTest=new MytagTest();
Annotation[] annotations=mytagTest.getClass().getMethod("info").getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof Mytag){
System.out.println("Tag is:"+annotation);
System.out.println("tag name():"+((Mytag) annotation).name());
System.out.println("tag age():"+((Mytag) annotation).age());
}
}
5.使用Annotation的示例:
java注释的一条原则:不会对程序构成任何影响;
其实Annotation十分简单,它是对源码增加的一些特殊标记,这些标记可以通过反射获取,当程序获取到这些特殊的标记之后,程序可以做出相应的处理(同时也可以忽略这些标记)
1) 可以通过Annotation为事件源绑定事件监听器
6.编译时处理Annotation:APT(Annotation processing tool)是一种处理注释的工具,它对源代码文件进行检测出其中的Annotation后,对Annotation进行额外的处理。
每个Annotation处理器都需要实现javax.annotation.processing包下的Processor接口。一个Annotation处理器可以处理一个或者多种Annotation.