Java注释(Annotation)详解
转自:http://www.hrmzone.cn/?p=528
?
注释:在一个类中可以有多个,类似于一个类可以有多个实例;
?????注释类型:是注释使用的结构,类似于类,仅有一个版本,因此多个注释可能使用相同的注释类型
?????jdk默认的三个注释:
???????1.Override注释:仅用于方法(不可用于类、包的生命或其他),指明注释的方法将覆盖超类中的方法(如果覆盖父类的方法而没有注
释就无法编译该类),注释还能确保注释父类方法的拼写是正确(错误的编写,编译器不认为是子类的新方法,而会报错)
???????2.@Deprecated注释:对不应再使用的方法进行注释,与正在声明为过时的方法放在同一行。使用被?????Deprecated注释的方法,编译器会
提示方法过时警告(”Warring”)
???????3.@SuppressWarnings注释:单一注释,可以通过数组提供变量,变量值指明要阻止的特定类型警告(忽略某些警告)。数组中的变量指明要阻止的警告@SuppressWarnings(value={”unchecked”,”fallthrough”}))
?????上面提到“单一注释”这个概念,他表示注释的类型,java中有三种类型的注释:
???????1.标记注释:由名称标记,未提供数据,@MarkerAnnotation
???????2.单一注释:与标记注释类似,但提供了一段很少一点的数据,很类似普通的java方法调用(@SingleValueAnnotation(”my data”)
???????3.完整注释:有多个数据成员,必须提供完整的语法(@FullAnnotation(var=”data value”,var2=”data value2″,var3=”data value3″))除了通过默认语法向注释提供值,还可以通过花括号为注释变量提供值数组,数组用”,”分割
自定义注释:
?????@interface:注释声明,定义注释类型(与默认的Override等三种注释类型类似),使用时与内置注释类型类似。使用定制注释类型时,要将注释定义类导入,或者直接引入包名。(定义注释类型和定义类非常类似,仅在注释类型名称前多了@interface),自定义注释类型中的变量如同类中的方法定义需要”()”,并以”;”结束
?????在使用有变量的注释类型时,需要制定数据类型的名称,但是如果注释类型中只有一个变量,最好将参数名称设为value,赋值时不用指定定名称而直接赋值如:变量名称(@AnnotationType(var value)),否则需要制定变量的名称(@Annotation(varname=varvalue))
?????注释类型的默认值:在定义注释的成员变量,需要在成员的声明后添加关键字(default)并对其赋值(默认值),注意默认值的类型必须和成员变量的类型一致。在使用该注释类型时,如果没有给该注释类型的成员变量赋值即用默认值
?????现在自定义注释来演示:
?????1.在eclipse中新建一个Annotation类:FirstAnno.java
package cn.hrmzone.anno;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(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)// 在使用@interface后,表明是自动继承子annotation类public @interface FirstAnno {//只有一个参数,可以直接命名为value,在使用时,可以不指定参数名而直接赋值;//而且,value()是类似方法,其实是自定义声明的一个参数,使用时是直接赋值和获取的。类似与Bean的getter和setter方法。//default:定义参数的默认值String value() default "FirstAnno";}
?????2.再新建一个Annotation类:SecondAnnotation:
package cn.hrmzone.anno;?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(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface SecondAnno {//注释中含有两个参数String name() default "Hrmzone";String url() default "hrmzone.cn";}
?????这个时候,估计对
?????@Documented
?????@Retention(RetentionPolicy.RUNTIME)
?????@Target(ElementType.METHOD)
?????这三个注释有很多疑问了吧,先将演示完成在解释:
?????3.新建一个使用以上定义的两个注释的类:Anno.java
package cn.hrmzone.anno;?@FirstAnno("http://hrmzone.cn")public class Anno {//不赋值注释中的参数,使用默认参数@SecondAnno()public String getDefault() {return "get default Annotation";}@SecondAnno(name="desktophrm",url="desktophrm.com")public String getDefine() {return "get define Annotation";}}
?????4.测试注释:AnnoTest.class
package cn.hrmzone.anno;?import java.io.File;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;?public class AnnoTest {public static void main(String[] args) throws ClassNotFoundException {//要使用到反射中的相关内容Class c=Class.forName("cn.hrmzone.anno.Anno");Method[] method=c.getMethods();boolean flag=c.isAnnotationPresent(FirstAnno.class);if(flag) {FirstAnno first=(FirstAnno) c.getAnnotation(FirstAnno.class);System.out.println("First Annotation:"+first.value()+"\n");}?List<Method> list=new ArrayList<Method>();for(int i=0;i<method.length;i++) {boolean f=method[i].isAnnotationPresent(SecondAnno.class);if(f) {list.add(method[i]);}}?for(Method m:list) {SecondAnno anno=m.getAnnotation(SecondAnno.class);System.out.println("second annotation's\nname:\t"+anno.name()+"\nurl:\t"+anno.url());}}}
?????测试的输出结果为:
First Annotation:http://hrmzone.cn?second annotation'sname:desktophrmurl:desktophrm.comsecond annotation'sname:Hrmzoneurl:hrmzone.cn
?????结合源文件中注释,想必对注释的应用有所了解。下面深入了解。
?????深入注释:
?????上面的两个Annotation类中有三个奇怪的注释,他们是元注释。
?????元注释:注释的注释,对注释进行注释,下面分别介绍这三个注释:
?????@Target:指定程序元定义的注释所使用的地方,它使用了另一个类:ElementType,是一个枚举类定义了注释类型可以应用到不同的程序元素以免使用者误用。看看java.lang.annotation 下的源代码:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
?????ElementType是一个枚举类型,指明注释可以使用的地方,看看ElementType类:
public enum ElementType { TYPE, // 指定适用点为 class, interface, enum FIELD, // 指定适用点为 field METHOD, // 指定适用点为 method PARAMETER, // 指定适用点为 method 的 parameter CONSTRUCTOR, // 指定适用点为 constructor LOCAL_VARIABLE, // 指定使用点为 局部变量 ANNOTATION_TYPE, //指定适用点为 annotation 类型 PACKAGE // 指定适用点为 package }
?????@Retention:这个元注释和java编译器处理注释的注释类型方式相关,告诉编译器在处理自定义注释类型的几种不同的选择,需要使用RetentionPolicy枚举类。此枚举类只有一个成员变量,可以不用指明成名名称而赋值,看Retention的源代码:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
?????类中有个RetentionPolicy类,也是一个枚举类,具体看代码:
public enum RetentionPolicy { SOURCE, // 编译器处理完Annotation后不存储在class中 CLASS, // 编译器把Annotation存储在class中,这是默认值 RUNTIME // 编译器把Annotation存储在class中,可以由虚拟机读取,反射需要 }
?????@Documented:是一个标记注释,表示注释应该出现在类的javadoc中,因为在默认情况下注释时不包括在javadoc中的。所以如果花费了大量的时间定义一个注释类型,并想描述注释类型的作用,可以使用它。注意他与@Retention(RetentionPolicy.RUNTIME)配合使用,因为只有将注释保留在编译后的类文件中由虚拟机加载,然后javadoc才能将其抽取出来添加至javadoc中。
?????@Inherited:将注释同样继承至使用了该注释类型的方法中(表达有点问题,就是如果一个方法使用了的注释用了@inherited,那么其子类的该方法同样继承了该注释)
注意事项:
?????1.所有的Annotation自动继承java.lang.annotation接口
?????2.自定义注释的成员变量访问类型只能是public、default;
?????3.成员变量的只能使用基本类型(byte、short、int、char、long、double、float、boolean和String、Enum、Class、annotations以及该类型的数据)
?????4.如果只有一个成员变量,最好将参数名称设为value,赋值时不用制定名称而直接赋值
?????5.在实际应用中,还可以使用注释读取和设置Bean中的变量。