标签:
今天学习如何开发一个自定义的Annotation。要想使Annotation有意义,还需要借用前几天学习的反射机制。
下面就开始今天的学习吧。
Annotation的定义格式。它类似于新创建一个接口类文件,但为了区分,我们需要将它声明为 @interface
public @interface Annotation名称{
数据类型 变量名称();
}
下面声明了一个Annotation
public @interface MyAnnotation {
}
使用这个Annotation
@MyAnnotation
public class AnnotationDemo{
public static void main(String []args){
}
}
注意上述Annotation没有参数,这样是没有任何意义的。要让它有意义,需要借用java的反射机制。
有内容的Annotation
public @interface MyAnnotation {
public String value();
}
在定义Annotation的时候使用了参数,就必须在使用其的时候清楚的指明变量的内容。
@MyAnnotation("Annotation")
public class AnnotationDemo{
public static void main(String []args){
}
}
或者明确赋给value
@MyAnnotation(value="Annotation")
public class AnnotationDemo{
public static void main(String []args){
}
}
可以设置一个参数,也可以设置多个参数。
public @interface MyAnnotation {
public String key();
public String value();
}
在使用的时候,传入要接收的参数。
@MyAnnotation(key="key",value="Annotation")
public class AnnotationDemo{
public static void main(String []args){
}
}
也可为一个参数传递多个值。
public String[] value(); 接收的时候以数组形式接收。 value={"Annotation","java"}
相信大家现在都跟我一样,很好奇这个自定义的Annotation里面并没有定义私有域value, public String[] value() 是一个函数,那么它是怎么接收值的呢。带着这个疑问继续学习。
上述Annotation都必须在使用的时候,给定参数。那么能不能设置默认参数呢,使用的时候使用默认值。答案是肯定的。
public @interface MyAnnotation { public String key() default "java"; //指定好了默认值 public String[] value() default "Annotation"; //指定好了默认值 }
在操作中,有时会对Annotation中的参数固定其取值范围,只能取固定的几个值,这个时候,就需要java中的枚举。
public @interface MyAnnotation { public Color key() default Color.BLACK; //指定好了默认值 public Color[] value() default Color.BLUE; //指定好了默认值 //在外部使用Annotation的时候,也需要固定枚举中的值 public enum Color{ RED , BLUE , BLACK } }
外部
//在外部使用Annotation的时候,也需要使用枚举中的值 @MyAnnotation(key=Color.RED) public class AnnotationDemo{ public static void main(String []args){ } }
上述是对自定义注释的简单定义与使用。
在Annotation中,可以使用Retention定义一个Annotation的保存范围。
@Documented @Retention(value=RetentionPolicy.RUNTIME) @Target(value=ElementType.ANNOTATION_TYPE) public @interface MyAnnotation { public Color key() default Color.BLACK; //指定好了默认值 public Color[] value() default Color.BLUE; //指定好了默认值 //在外部使用Annotation的时候,也需要固定枚举中的值 public enum Color{ RED , BLUE , BLACK } }
1、@Documented 类和方法的Annotation缺省情况下是不出现在javadoc中的,为了加入这个性质使用@Documented
2、@Retention
Annotation的作用范围通过RetentionPolicy来指定,RetentionPolicy有三个范围:
RetentionPolicy.SOURCE // 此Annotation类型的信息只会保存在程序原文件之中(*.java),编译之后不会保存在编译好的文件中(*.class)
RetentionPolicy.CLASS // 此Annotation类型的信息会保存在程序原文件之中(*.java),编译之后会保存在编译好的文件中(*.class),但在执行的时候这些Annotation信息将不会加载到JVM虚拟机中,如果 一个Annotation没有指定范围,则默认是此范围
RetentionPolicy.RUNTIME //顾名思义了,这些Annotation类型信息将会一直保存到执行时,加载到JVM虚拟中。
在这三个范围中,我们最需要关心的就是 RetentionPolicy.RUNTIME了,因为它会在执行的时候起作用。
那么前面文章中提到的系统内建的三种Annotation都是什么作用范围呢。
@Override 定义的时候采用的是@Retention(value=RetentionPolicy.SOURCE)
@Deprecated 定义的时候采用的是@Retention(value=RetentionPolicy.RUNTIME)
@SuppressWarnings 定义的时候采用的是@Retention(value=RetentionPolicy.SOURCE)
3、@Target
@Target注解表明某个注解应用在哪些目标上,可选择如下范围,根据因英文名,相信大家都能看懂。
ElementType.TYPE (class, interface, enum)
ElementType.FIELD (instance variable)
ElementType.METHOD
ElementType.PARAMETER
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.ANNOTATION_TYPE (应用于另一个注解上)
ElementType.PACKAGE
4、@Inherited
@Inherited 表明是否一个使用某个annotation的父类可以让此annotation应用于子类。
示例代码如下,定义@Inherited
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(value=RetentionPolicy.RUNTIME) //必须指定为RUNTIME,否则不起作用 @Target({ElementType.TYPE,ElementType.METHOD, ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE, ElementType.PACKAGE}) @Inherited public @interface MyAnnotation { public String key(); public String value(); }
在Stu子类中依然可取得父类中定义的注释信息。
interface A{ public String sayHello(); } @MyAnnotation(key="key",value="value") class Per implements A{ public String sayHello(){ return "hello world"; } } class Stu extends Per{ public String sayHello(){ return "hello world"; } } public class AnnotationDemo{ public static void main(String []args){ Class <?> c = null ; c = new Stu().getClass() ; if(c.isAnnotationPresent(MyAnnotation.class)){ // 判断是否是指定的Annotation MyAnnotation mda = null ; mda = c.getAnnotation(MyAnnotation.class) ; // 得到指定的Annotation String key = mda.key() ; // 取出设置的key String value = mda.value() ; // 取出设置的value System.out.println("key = " + key) ; System.out.println("value = " + value) ; } } }
下面就是我最关心的了,如何利用反射在运行时候获得注释信息。
反射与Annotation
一个Annotation要想变得有意义,就需要结合反射机制。在Class类中,有如下与Annotation相关的方法。
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) //如果一个元素存在注释,则取得其全部注释
public Annotation[] getAnnotations() //返回此元素上的所有注释
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) //返回直接存放在此元素上的所有注释
public boolean isAnnotation() //判断元素是否表示一个注释
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) //判断一个元素上是否存在注释
等等……
下面通过代码演示如何通过反射取得Annotation
import java.lang.annotation.Annotation; import java.lang.reflect.Method; interface A{ public String sayHello(); } class Per implements A{ @SuppressWarnings("unchecked") @Override @Deprecated //只有它在运行时有效 public String sayHello(){ return "hello world"; } } public class AnnotationDemo{ public static void main(String []args){ Class <?> c = null ; c = new Per().getClass() ; Method toM = null; try { toM = c.getMethod("sayHello") ; // 找到sayHello()方法 } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } Annotation an[] = toM.getAnnotations() ; // 取得全部的Annotation for(Annotation a:an){ // 使用 foreach输出 System.out.println(a) ; } } }
输出结果为@java.lang.Deprecated(),这显而易见,前面已经提到了,只有@Deprecated 在运行时有效。
所以要想使我们自定义的Annotation在运行时有效,必须在定义的时候指定RetentionPolicy.RUNTIME。
如何取得定义的注释信息中的值呢。
在定义的时候
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(value=RetentionPolicy.RUNTIME) //必须指定为RUNTIME,否则不起作用 @Target(value=ElementType.METHOD) public @interface MyAnnotation { public String key(); public String value(); }
取出注释信息中的值
import java.lang.reflect.Method; interface A{ public String sayHello(); } class Per implements A{ @MyAnnotation(key="key",value="value") public String sayHello(){ return "hello world"; } } public class AnnotationDemo{ public static void main(String []args){ Class <?> c = null ; c = new Per().getClass() ; Method toM = null; try { toM = c.getMethod("sayHello"); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(toM.isAnnotationPresent(MyAnnotation.class)){ // 判断是否是指定的Annotation MyAnnotation mda = null ; mda = toM.getAnnotation(MyAnnotation.class) ; // 得到指定的Annotation String key = mda.key() ; // 取出设置的key String value = mda.value() ; // 取出设置的value System.out.println("key = " + key) ; System.out.println("value = " + value) ; } } }
通过以上代码就可以取出在注释信息中的值。
总结
Annotation在使用中,肯定是结合反射,设定一些内容到方法中去,以完成特定的功能。
Java中的Annotation (二、自定义Annotation)
标签:
原文地址:http://www.cnblogs.com/maydayit/p/4237277.html