?? 按照自己定的学习计划,今天是该写点什么了。
? 在上篇文章里提到的是JUnit的学习,其中就涉及到了一些内置的annotation,如@Test、@Ignore等。现在我就结合个人的理解谈下如何自定义自己的annotation。
? annotation能被用来为某个程序元素(类、方法、成员变量等)关联任何的信息,但annotaion不能影响程序代码的执行,无论增加、删除annotation,代码都始终如一的执行。另外,尽管一些annotation通过java的反射api方法在运行时被访问,而java语言解释器在工作时忽略了这些annotation。正是由于java虚拟机忽略了annotation,导致了 annotation类型在代码中是“不起作用”的;只有通过某种配套的工具才会对annotation类型中的信息进行访问和处理,因而使用简便。
? 先说下定义annotation的语法。@interface是一个关键字,在自定义自己annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字,形如“public @interface MyAnnotation{ }”,以下是定义的几个示例:
? 1.无任何方法/属性Annotation
??
2,具有一个方法getValue( )的Annotation
3,? 具有一个特殊方法value( )的Annotation(特殊性下面会提到)
4,具有一个方法和属性的Annotation
5,具有多个方法的Annotation
在上面的例子中可以看到,其实申明一个annotation和interface、class不同的是关键字@interface,而且它还可以对方法设置默认的返回值,如上图的“? public int getSingleNumber() default 0 ;???? ”,设置默认返回0。还有个显著的不同就是在申明每个Annotation的上面有几个标签@Target、@Retention。
? annotation的target是一个被标注的程序元素。target说明了annotation所修饰的对象范围:annotation可被用于 packages、types(类、接口、枚举、annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在annotation类型的声明中使用了target可更加明晰其修饰的目标。annotation的retention定义了该annotation被保留的时间长短:某些annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为annotation与class在使用上是被分离的)。使用这个meta-annotation可以对 annotation的“生命周期”限制。RetentionPolicy是一个enum类型,共有三个值,分别是SOURCE,CLASS 和 RUNTIME。SOURCE代表的是这个Annotation类型的信息只会保留在程序源码里,源码如果经过了编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里面。ClASS的意思是这个Annotation类型的信息保留在程序源码里,同时也会保留在编译好的.class文件里面,在执行的时候,并不会把这一些信息加载到虚拟机(JVM)中去.注意一下,当你没有设定一个Annotation类型的Retention值时,系统默认值是CLASS. 第三个,是RUNTIME,表示在源码、编译好的.class文件中保留信息,在执行的时候会把这一些信息加载到JVM中去的。
? 下面是如何使用自己定义的annotation:
?
从上面的测试代码可以看出:使用一个annotation的语法是
由“@+annotation类型名称+(..逗号分割的name-value对...)”组成。其中成员可以按照任何的顺序。如果annotation 类型定义了某个成员的默认值,则这个成员可以被省略。成员值必须为编译时常量、内嵌的annotation或者数组。
上面提到了一个特殊性,大家可以对比下上面的testMethod2和testMethod3上的annotation,会发现@OneMethodSpecialInAnnotation的值”Hello,world!”是没有匹配的name,那么这个值到底传给谁了?其实这里有一个约定。如果没有写属性名的值,而这个注释又有value属性,就将这个值赋给value属性,相当于是(value="Hello,world!")。
main方法是一个对上面进行测试的,其输出是:
the method testMethod1 is not wired!!
the method testMethod2 is not wired!!
the method testMethod3 is not wired!!
the method testMethod4 is not wired!!
the method testMethod5 is wired!!
为什么输出“testMethod5 is wired”呢?因为执行了这句代码:if (method.isAnnotationPresent(MultiMethodsInAnnotation.class))。@MultiMethodsInAnnotation是在testMethod5 上的,如果换成其他的annotation,也会得到相应的提示。isAnnotationPresent()方法对于检查marker annotation是十分有用的,因为marker annotation没有成员变量,所以我们只要知道class的方法是否使用了annotation修饰就可以了。而当处理具有成员的 annotation时,我们通过使用getAnnotation()方法来获得annotation的成员信息(成员名称、成员值)。这里我们看到了一套优美的java annotation系统:如果annotation存在,那么实现了相应的annotation类型接口的对象将被getAnnotation()方法返回,接着调用定义在annotation类型中的成员方法可以方便地获得任何成员值。
? 现在我们再来个High点的,如何访问一个annotation里的各个方法,如下:
?
至此,感觉自己学到的也就这么多了,也不知道是不是太肤浅。相信Annotation技术在不久的将来将得到更好的发展!至于在实际测试中用到的DBunit中的@DataSet macker是如何将场景数据自动插入到数据库的源码学习,将在以后的总结中给出。
最后,谢谢各位能抽出时间看完这篇文章,文中如有不当,请指正,谢谢!
O(∩_∩)O