java 注解学习

基本的Annotation

  • @Override

    强制子类复写父类的方法

  • @Deprecated 标记过时

    表示某个程序元素(类,方法)过时。编译器会出现警告

  • @SuppressWarnings 抑制编译器的警告
  • @SafeVarargs 这个是java7加入,代表堆污染的警告
    示例情况:
    1
    2
    3
    4
    5
    6
    7
    public static void faultyMethod(List<String> ...listStrArray){
    List[] listArray=listStrArray;
    List<Integer> myList=new ArrayList<Integer>();
    myList.add(new Random().nextInt(100));
    listArray[0]=myList;
    String s=listArray[0].get(0);
    }

注意:java语言并不支持泛型数组,上面导致堆污染。

如果想抑制上面的警告,只需要用@SuppressWarnings("unchecked")修饰。

使用@Retention

只能休市一个Anootation定义,用于指定被休市的Annotation可以保留多长时间。并且保留一个value的成员变量。
value的值可以有三个:

  • RetentionPolicy.CLASS 保留到编译后class的阶段,运行不保留
  • RetentionPolicy.RUNTIME 保留到运行时
  • RetentionPolicy.SOURCE: 值保留到源代码中。
1
2
@Retention(value=RetenionPolicy.RUNTIME)
public @interface Testtable{}

可以直接指定value的值,上面写为@Retention(RetenionPolicy.RUNTIME).

使用@Target

只能修改Annotation的定义,可直接指定value的值,不需要name=value的形式。
value可选变量:

  • ElementType.ANNOTATION_TYPE 只能修饰Annotation
  • ElementType.CONSTRUCTOR 只能修饰构造器
  • ElementType.FIELD 只能修饰成员变量
  • ElementType.LOCAL_VARIABLE 只能修饰局部变量
  • ElementType.METHOD 只能修饰方法定义
  • ElementType.PACKAGE 只能修饰包定义
  • ElementType.PARAMETER 只能修饰参数
  • ElementType.TYPE 只能修饰类,接口,枚举定义

@Documented

修饰的Annotation类将被javac工具提取为文档。

使用@Inherited

修饰的Annotation类具有继承性。即:基类使用@Inherited,那么子类自动默认使用@Inherited修饰

定义Annotation

使用@interface关键字:

1
public @interface Test{}

现在可以用@Test进行修饰类,方法,变量,接口等任何位置

1
2
3
4
public class MyClass{
@Test
public void info(){}
}

指定成员变量

其成员定义:以方法的形式来定义

1
2
3
4
public @interface Test{
String name();
int age();
}

更定义接口的方法非常相似。注意:定义成员变量后,使用的时候必须指定值

指定成员变量的默认值

使用default指定初始值

1
2
3
4
public @interface Test{
string name() default "trity";
int age() default 32;
}

使用的时候,不指定值,则为默认值。

提取Annotation信息

使用java.lang.reflect包下反射的工具类。通过反射来获取对应的注解信息。
三个方法访问Annotation的信息

  • getAnnotation(); 返回指定的注解
  • Annotation[] getAnnotations(); 返回存在的所有注解
  • boolean isAnnotationPresent(); 是否存在指定的注解。
1
2
3
4
5
6
7
8
9
Annotation[] array=Class.forname("MyClass").getMethod("info").getAnnotation();
//遍历所有的注解
for(Annotation an:array){
System.out.println(an);
//通过强制转换得到对应的成员变量
if(an instanceof Test){
System.out.println("an.getName()",((Test)an).method());
}
}

使用Annotation的示例

定义:

1
2
3
@Retention(RetentinoPolicy.RUNTIME)
@Taeget(ElementType.METHOD)
public @Interface Testable{}

使用:

1
2
3
4
5
6
7
8
public class MyTest{
@Testable
public void m1(){};

public void m2(){};
@Testable
public void m3(){};
}

对应的注解处理工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ProcessorTest{
public static void process(String clazz){
int passed=0;
int failed=0;
for(Method m: Class.forName(clazz).getMethods()){
if(m.isAnnotationPresent(Testable.class)){
try{
//调用m方法
m.invoke(null);
passed++;
}catch(Exception e){
failed++;
}
//输出统计结果
System.out.....
}}}}

扩展:按钮事件的监听。

编译处理Annotation

使用APT工具,简化开发者的工作量,因为APT可以在编译程序源代码的同时生成一些附属文件。