??xml version="1.0" encoding="utf-8" standalone="yes"?>每日更新成人在线视频,国产亚洲1区2区3区,国产伦精品一区二区三区视频金莲http://www.aygfsteel.com/aczreg/category/43651.html先做事情Q再看心情…?/description>zh-cnTue, 19 Jan 2010 07:32:27 GMTTue, 19 Jan 2010 07:32:27 GMT60Java Annotation手册 http://www.aygfsteel.com/aczreg/archive/2010/01/19/310084.html咖啡企鹅咖啡企鹅Tue, 19 Jan 2010 07:30:00 GMThttp://www.aygfsteel.com/aczreg/archive/2010/01/19/310084.htmlhttp://www.aygfsteel.com/aczreg/comments/310084.htmlhttp://www.aygfsteel.com/aczreg/archive/2010/01/19/310084.html#Feedback0http://www.aygfsteel.com/aczreg/comments/commentRss/310084.htmlhttp://www.aygfsteel.com/aczreg/services/trackbacks/310084.htmlhttp://blog.matrix.org.cn/page/cleverpig)
原文:http://www.matrix.org.cn/resource/article/44/44055_Java+Annotation+Reflect.html
关键?java,annotation,reflect

前言Q?/span>
在上文?a >《Java Annotation入门?/a>中概要性的介绍了Annotation的定义、用,范围늛较广Q但是深度不够。所以作者在《Java Annotation入门》后Ql整理了Annotation的概念和知识点,与喜Ƣresearch的朋友们׃n?br />
阅读提示Q文中提到的E序成员或者程序元素是一个概念,指组成程序代码的单元Q如cR方法、成员变量?/span>

一、AnnotationI竟是什么?

Annotation 提供了一条与E序元素兌M信息或者Q何元数据QmetadataQ的途径。从某些斚w看,annotation像修饰W一栯使用Qƈ应用于包、类 型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation?#8220;name=value”l构对中? annotationcd是一U接口,能够通过java反射API的方式提供对其信息的讉K?br />
annotation能被用来为某个程序元 素(cR方法、成员变量等Q关联Q何的信息。需要注意的是,q里存在着一个基本的潜规则:annotaion不能影响E序代码的执行,无论增加、删? annotationQ代码都始终如一的执行。另外,管一些annotation通过java的反apiҎ在运行时被访问,而java语言解释器在 工作时忽略了q些annotation。正是由于java虚拟机忽略了annotationQ导致了annotationcd在代码中?#8220;不v作用”的; 只有通过某种配套的工h会对annotationcd中的信息q行讉K和处理。本文中涵盖标准的annotation和meta- annotationcdQ陪伴这些annotationcd的工hjava~译器(当然要以某种Ҏ的方式处理它们)?br />
׃上述? 因,annotation在用时十分ѝ一个本地变量可以被一个以NonNull命名的annotationcd所标注Q来作ؓ对这个本地变量不能被 赋予null值的断言。而我们可以编写与之配套的一个annotation代码分析工具Q用它来对h前面变量的代码进行解析,q且试验证q个断言? 当然q些代码q不必自q写。在JDK安装后,在JDK/bin目录中可以找到名?#8220;apt”的工P它提供了处理annotation的框Ӟ它启动后 扫描源代码中的annotationQƈ调用我们定义好的annotation处理器完成我们所要完成的工作Q比如验证前面例子中的断aQ。说到这里, annotation的强大功能似乎可以替代XDocletq类的工具了Q随着我们的深入,大家会更加坚信这一炏V?br /> 注:详细描述请参看jsr250规范Q?br /> http://www.jcp.org/aboutJava/communityprocess/pfd/jsr250/

二、Annotation的定义:

q? D|字开始介lannotation相关技术。在此大家将看到java5.0的标准annotationcdQ这U标准类型就是前文中所说的“内徏”c? 型,它们可以直接被javac支持。可喜的是,在java6.0beta版中的javac已经加入了对自定义annotation的支持?br />
1。Annotation的概念和语法Q?/span>

首先Q关键的概念是理解annotation是与一个程序元素相兌信息或者元数据的标注。它从不影响javaE序的执行,但是对例如编译器警告或者像文档生成器等辅助工具产生影响?br /> 下面是常用的annotation列表Q我们应该注意在annotation和annotationcd之间的不同:

A.annotationQ?/span>
annotation 使用了在java5.0所带来的新语法Q它的行为十分类似public、finalq样的修饰符。每个annotationh一个名字和成员个数 >=0。每个annotation的成员具有被UCؓname=value对的名字和|像javabean一PQname=value装蝲? annotation的信息?br />
B.annotationcdQ?/span>
annotation cd定义了annotation的名字、类型、成员默认倹{一个annotationcd可以说是一个特D的java接口Q它的成员变量是受限制的Q而声 明annotationcd旉要用新语法。当我们通过java反射api讉KannotationӞq回值将是一个实C该annotationc? 型接口的对象Q通过讉Kq个对象我们能方便的讉K到其annotation成员。后面的章节提到在java5.0的java.lang包里包含?个标 准annotationcd?br />
C.annotation成员Q?/span>
annotation 的成员在annotationcd中以无参数的Ҏ的Ş式被声明。其Ҏ名和q回值定义了该成员的名字和类型。在此有一个特定的默认语法Q允许声明Q? annotation成员的默认|一个annotation可以name=value对作为没有定义默认值的annotation成员的|当然也可 以用name=valueҎ覆盖其它成员默认倹{这一Ҏ些近似类的承特性,父类的构造函数可以作为子cȝ默认构造函敎ͼ但是也可以被子类覆盖?br />
D.marker annotationcdQ?/span>
一个没有成员定义的annotationcd被称为marker annotation。这Uannotationcd仅用自w的存在与否来ؓ我们提供信息。如后面要说的Override?br />
E.meta-annotationQ?/span>
meta -annotation也称为元annotationQ它是被用来声明annotationcd的annotation。Java5.0提供了一些标准的 ?annotationcd。下面介l的target、retention是meta-annotation?br />
F.targetQ?/span>
annotation 的target是一个被标注的程序元素。target说明了annotation所修饰的对象范_annotation可被用于packages? typesQ类、接口、枚举、annotationcdQ、类型成员(Ҏ、构造方法、成员变量、枚丑ր|、方法参数和本地变量Q如循环变量、catch 参数Q。在annotationcd的声明中使用了target可更加明晰其修饰的目标?br />
G.retentionQ?/span>
annotation 的retention定义了该annotation被保留的旉长短Q某些annotation仅出现在源代码中Q而被~译器丢弃;而另一些却被编译在 class文g中;~译在class文g中的annotation可能会被虚拟机忽略,而另一些在class被装载时被dQ请注意q不影响class 的执行,因ؓannotation与class在用上是被分离的)。用这个meta-annotation可以对annotation?#8220;生命周期” 限制?br />
H.metadataQ?/span>
׃metadata被广泛用于各种计算机开发过E中Q所以当我们在这里谈论的metadata卛_数据通常指被annotation装蝲的信息或者annotation本n?br />
2。用标准AnnotationQ?/span>
java5.0在java.lang包中定义?U标准的annotationcdQ?br />
A.OverrideQ?/span>
java.lang.Override 是一个marker annotationcdQ它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断a的作用。如果我们用了q种annotation在一? 没有覆盖父类Ҏ的方法时Qjava~译器将以一个编译错误来警示?br /> q个annotaton常常在我们试图覆盖父cL法而确又写错了Ҏ名时发挥威力?br />
使用Ҏ极其单:在用此annotation时只要在被修饰的Ҏ前面加上@Override?br /> 下面的代码是一个用@Override修饰一个企N载父cȝtoStringҎQ而又存在拼写错误的sampleQ?br /> 清单1Q?/strong>
@Override



public String toSting() {   // 注意Ҏ名拼写错?br />


    return "[" + super.toString() + "]";



}





B.DeprecatedQ?/span>
同样 Deprecated也是一个marker annotation。当一个类型或者类型成员用@Deprecated修饰的话Q编译器不鼓励使用q个被标注的E序元素。而且q种修饰h一定的 “延箋?#8221;Q如果我们在代码中通过l承或者覆盖的方式使用了这个过时的cd或者成员,虽然l承或者覆盖后的类型或者成员ƈ不是被声明ؓ @DeprecatedQ但~译器仍然要报警?br /> 值得注意Q@Deprecatedq个annotationcd和javadoc中的 @deprecatedq个tag是有区别的:前者是java~译器识别的Q而后者是被javadoc工具所识别用来生成文档Q包含程序成员ؓ什么已l过 时、它应当如何被禁止或者替代的描述Q?br /> 在java5.0Qjava~译器仍然象其从前版本那样寻找@deprecatedq个javadoc tagQƈ使用它们产生警告信息。但是这U状况将在后l版本中改变Q我们应在现在就开始用@Deprecated来修饰过时的Ҏ而不? @deprecated javadoc tag?br /> 清单2Q?/strong>
下面是一D用@Deprecated的代码:



/**



* q里是javadoc的@deprecated声明.



* @deprecated No one has players for this format any more.  Use VHS instead.



*/



@Deprecated public class Betamax { ... }





C.SuppressWarningsQ?/span>
@SuppressWarnings 被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0Qsun提供的javac~译器ؓ我们提供?Xlint选项来ɾ~? 译器对合法的E序代码提出警告Q此U警告从某种E度上代表了E序错误。例如当我们使用一个generic collectionc而又没有提供它的cdӞ~译器将提示?unchecked warning"的警告?br />
通常当这U情况发生时Q我们就需要查扑ּ赯告的代码。如果它真的表示错误Q我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的caseQ那么我们就应增加一个默认的case来避免这U警告?br /> ? 仿,有时我们无法避免q种警告Q例如,我们使用必须和非generic的旧代码交互的generic collectioncLQ我们不能避免这个unchecked warning。此时@SuppressWarningpz上用场了,在调用的Ҏ前增加@SuppressWarnings修饰Q告诉编译器停止Ҏ Ҏ的警告?br /> SuppressWarning不是一个marker annotation。它有一个类型ؓString[]的成员,q个成员的gؓ被禁止的警告名。对于javac~译器来Ԍ?Xlint选项有效的警? 名也同样对@SuppressWarings有效Q同时编译器忽略掉无法识别的警告名?br />
annotation语法允许在annotation名后跟括P括号中是使用逗号分割的name=value对用于ؓannotation的成员赋|
清单3Q?/strong>
@SuppressWarnings(value={"unchecked","fallthrough"})



public void lintTrap() { /* sloppy method body omitted */ }





在这个例子中SuppressWarnings annotationcd只定义了一个单一的成员,所以只有一个简单的value={...}作ؓname=value寏V又׃成员值是一个数l,故用大括号来声明数l倹{?br />
注意Q我们可以在下面的情况中~写annotationQ当annotation只有单一成员Qƈ成员命名?value="。这时可以省?value="。比如将上面的SuppressWarnings annotationq行~写Q?br /> 清单4Q?/strong>
@SuppressWarnings({"unchecked","fallthrough"})




如果SuppressWarnings所声明的被止警告个数Z个时Q可以省d括号Q?br />
@SuppressWarnings("unchecked")





3。Annotation语法Q?/span>

在上一个章节中Q我们看C写marker annotation和单一成员annotation的语法。下面本人来介绍一下完整的语法Q?br />
annotation ?#8220;@+annotationcd名称+(..逗号分割的name-value?..)”l成。其中成员可以按照Q何的序。如果annotation cd定义了某个成员的默认|则这个成员可以被省略。成员值必Mؓ~译时常量、内嵌的annotation或者数l?br />
下面我们定义一? annotationcd名ؓReviewsQ它有一个由@Review annotation数组构成的成员。这个@Review annotationcd有三个成员:"reviewer"是一个字W串Q?comment" 是一个具有默认值的可选的字符Ԍ"grade"是一个Review.Grade枚Dcd倹{?br /> 清单5Q?/strong>
@Reviews({  // Single-value annotation, so "value=" is omitted here



    @Review(grade=Review.Grade.EXCELLENT,



            reviewer="df"),



    @Review(grade=Review.Grade.UNSATISFACTORY,



            reviewer="eg",



            comment="This method needs an @Override annotation")



})




annotation语法的另一个重要规则是没有E序成员可以有多于一个的同一annotation实例。例如在一个类中简单的攄多个@Review annotation。这也是在上面代码中定义@Reviews annotationcd数组的原因?br />
4。Annotation成员cd和|

annotation成员必须是非I的~译时常量表辑ּ。可用的成员cd为:primitivecd? String, Class, enumeratedcd, annotationcd, 和前面类型的数组?br />
下面我们定义了一个名为UncheckedExceptions 的annotationcdQ它的成员是一个扩展了RuntimeExceptioncȝcLl?br /> 清单6Q?/strong>
@UncheckedExceptions({



    IllegalArgumentException.class, StringIndexOutOfBoundsException.class



})





5。Annotation的目标:

annotation通常被放在类型定义和成员定义的前面。然而它也出现在package、方法参数、本地变量的前面。下面,我们来讨Z下这些不大常用的写法Q?br />
package annotation出现在package声明的前面?br /> 下面的例子package-info.java中不包含M的公q型定义,却包含一个可选的javadoc注释?br /> 清单7Q?/strong>
/**



* This package holds my custom annotation types.



*/



@com.davidflanagan.annotations.Author("David Flanagan")



package com.davidflanagan.annotations;




当package -info.java文g被编译时Q它生名为包含annotationQ特D的接口Q声明的package-info.class的类。这个接口没? 成员Q它的名字package-info不是一个合法的java标识Q所以它不能用在java源代码中。这个接口的存在只是单的被看作一个ؓ package annotation准备的占位符?br />
用于修饰Ҏ参数、catch参数、本地变量的annotation只是单的出现 在这些程序成员的修饰W位|。javacL件格式没有ؓ本地变量或者catch参数存储annotation作准备,所以这些annotationL? 留在源代码别(source retentionQ;Ҏ参数annotation能够保存在类文g中,也可以在保留到运行时?br />
最后,h意,枚Dcd定义中不允许M的修饰符修饰其枚丑ր{?br />
6。Annotation和默认|
在Annotation 中,没有默认值的成员必须有一个成员倹{而如何理解默认值是如何被处理就是一个很重要的细节:annotationcd所定义的成员默认D存储? class文g中,不被~译到annotation里面。如果我们修改一个annotationcd使其成员的默认值发生了改变Q这个改变对于所有此cd 的annotation中没有明提供成员值的成员产生影响Q即修改了该成员的成员|。即使在annotationcd使其成员的默认D改变? annotation从没被重新编译过Q该cd的annotation(改变前已l被~译?也受到媄响?br />
三、Annotation工作原理Q?/span>

Annotation与反?/span>
在java5.0 中Java.lang.reflect提供的反API被扩充了dq行时annotation的能力。让我们回顾一下前面所讲的Q一? annotationcd被定义ؓruntime retention后,它才是在q行时可见,当class文g被装载时被保存在class文g中的annotation才会被虚拟机d。那? reflect是如何帮助我们访问class中的annotation呢?

下文在java.lang.reflect用于 annotation的新Ҏ,其中java.lang.reflect.AnnotatedElement是重要的接口Q它代表了提供查? annotation能力的程序成员。这个接口被java.lang.Package、java.lang.Class实现Qƈ间接地被MethodcR? ConstructorcRjava.lang.reflect的Fieldcd现。而annotation中的Ҏ参数可以通过MethodcR? ConstructorcȝgetParameterAnnotations()Ҏ获得?br />
下面的代码用了AnnotatedElementcȝisAnnotationPresent()Ҏ判断某个Ҏ是否h@Unstable annotationQ从而断a此方法是否稳定:
清单8Q?/strong>
import java.lang.reflect.*;







Class c = WhizzBangClass.class;                          



Method m = c.getMethod("whizzy", int.class, int.class);  



boolean unstable = m.isAnnotationPresent(Unstable.class);




isAnnotationPresent ()Ҏ对于查marker annotation是十分有用的Q因为marker annotation没有成员变量Q所以我们只要知道class的方法是否用了annotation修饰可以了。而当处理h成员? annotationӞ我们通过使用getAnnotation()Ҏ来获得annotation的成员信息(成员名称、成员|。这里我们看C一 套优的java annotationpȝQ如果annotation存在Q那么实C相应的annotationcd接口的对象将被getAnnotation()Ҏ q回Q接着调用定义在annotationcd中的成员Ҏ可以方便地获得Q何成员倹{?br />
回想一下,前面介绍的@Reviews annotationQ如果这个annotationcd被声明ؓruntime retention的话Q我们通过下面的代码来讉K@Reviews annotation的成员|
清单9Q?/strong>
AnnotatedElement target = WhizzBangClass.class; //获得被查询的AnnotatedElement



// 查询AnnotatedElement的@Reviews annotation信息



Reviews annotation = target.getAnnotation(Reviews.class);



// 因ؓ@Reviews annotationcd的成员ؓ@Review annotationcd的数l,



// 所以下面声明了Review[] reviews保存@Reviews annotationcd的value成员倹{?br />


Review[] reviews = annotation.value();



// 查询每个@Review annotation的成员信?br />


for(Review r : reviews) {



    Review.Grade grade = r.grade();



    String reviewer = r.reviewer();



    String comment = r.comment();



    System.out.printf("%s assigned a grade of %s and comment '%s'%n",



                      reviewer, grade, comment);



}





四、如何自定义AnnotationQ?/span>

1Q详解annotation与接口的异同Q?/span>
因ؓannotationcd是一个非凡的接口Q所以两者之间存在着某些差异Q?br />
A.Annotationcd使用关键字@interface而不是interface?/span>
q个关键字声明隐含了一个信息:它是l承了java.lang.annotation.Annotation接口Qƈ非声明了一个interface?br />
B.Annotationcd、方法定义是独特的、受限制的?/span>
Annotation cd的方法必d明ؓ无参数、无异常抛出的。这些方法定义了annotation的成员:Ҏ名成Z成员名,而方法返回值成Z成员的类型。而方法返? 值类型必Mؓprimitivecd、Classcd、枚丄型、annotationcd或者由前面cd之一作ؓ元素的一l数l。方法的后面可以使用 default和一个默认数值来声明成员的默认|null不能作ؓ成员默认|q与我们在非annotationcd中定义方法有很大不同?br /> Annotationcd和它的方法不能用annotationcd的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotationcd中用genericQ因为此Ҏ能够用类转换各U类型{换ؓClass?br />
C.Annotationcd又与接口有着q似之处?/span>
它们可以定义帔R、静态成员类型(比如枚Dcd定义Q。Annotationcd也可以如接口一般被实现或者ѝ?br />
2Q实例:
下面Q我们将看到如何定义annotationcd的example。它展示了annotationcd声明以及@interface与interface之间的不同:
清单10Q?/strong>
package com.davidflanagan.annotations;



import java.lang.annotation.*;







/**



* 使用annotation来描q那些被标注的成员是不稳定的Q需要更?br />


*/



@Retention(RetentionPolicy.RUNTIME)



public @interface Unstable {}





下面的另一个example只定义了一个成员。ƈ通过这个成员命名ؓvalueQ我们可以方便的用这Uannotation的快捷声明方式:
清单11Q?/strong>
/**



* 使用Authorq个annotation定义在程序中指出代码的作?br />


*/



public @interface Author {



    /** q回作者名 */



    String value();



}





以下的example更加复杂。Reviews annotationcd只有一个成员,但是q个成员的类型是复杂的:由Review annotationl成的数l。Review annotationcd?个成员:枚Dcd成员grade、表CReview名称的字W串cd成员Reviewer、具有默认值的字符串类型成? Comment?br /> 清单12Q?/strong>
import java.lang.annotation.*;



        



/**



* Reviews annotationcd只有一个成员,



* 但是q个成员的类型是复杂的:由Review annotationl成的数l?br />


*/



@Retention(RetentionPolicy.RUNTIME)



public @interface Reviews {



    Review[] value();



}







/**



* Review annotationcd?个成员:



* 枚Dcd成员grade?br />


  * 表示Review名称的字W串cd成员Reviewer?br />


  * h默认值的字符串类型成员Comment?br />


*/



public @interface Review {



    // 内嵌的枚丄?br />


    public static enum Grade { EXCELLENT, SATISFACTORY, UNSATISFACTORY };







    // 下面的方法定义了annotation的成?br />


    Grade grade();                



    String reviewer();          



    String comment() default "";  



}





最后,我们来定义一个annotationҎ用于|列出类q行中所有的unchecked异常Q上文已l提到这U情况不一定是错误Q? q个 annotationcd一个数l作Z唯一的成员。数l中的每个元素都是异常类。ؓ了加强对未检查的异常Q此cd帔R是在q行时抛出)q行报告Q我? 可以在代码中对异常的cdq行限制Q?br /> 清单13Q?/strong>
public @interface UncheckedExceptions {



    Class<? extends RuntimeException>[] value();



}





五、Meta-Annotation

Annotation cd可以被它们自己所标注。Java5.0定义?个标准的meta-annotationcdQ它们被用来提供对其它annotationcd作说明? q些cd和它们所支持的类在java.lang.annotation包中可以扑ֈ。如果需要更详细的信息可以参考jdk5.0手册?br />
1Q再谈Target
? 为meta-annotationcd的Target,它描qCannotation所修饰的程序成员的cd。当一个annotationcd没有 TargetӞ它将被作为普通的annotation看待。当它修饰一个特定的E序成员Ӟ它将发挥其应用的作用Q例如:Override用于修饰? 法时Q增加了@Targetq个meta-annotation׃ɾ~译器对annotation作检查,从而去掉修饰错误类型的Override?br />
Target meta-annotationcd有唯一的value作ؓ成员。这个成员的cd是java.lang.annotation.ElementType[]cd的,ElementTypecd是可以被标注的程序成员的枚Dcd?br />
2QRetention的用?/span>
? 们在文章的开头曾l提到过RetentionQ但是没有详l讲解。Retention描述了annotation是否被编译器丢弃或者保留在class? Ӟ如果保留在class文g中,是否在class文g被装载时被虚拟机d。默认情况下Qannotation被保存在class文g中,但在q行时ƈ 不能被反访问。Retentionh三个取|source、class、runtimeQ这些取值来? java.lang.annotation.RetentionPolicy的枚丄型倹{?br />
Retention meta-annotationcd有唯一的value作ؓ成员Q它的取值来自java.lang.annotation.RetentionPolicy的枚丄型倹{?br />
3QDocumented
Documented是一个meta-annotationcdQ用于描q其它类型的annotation应该被作标注的程序成员的公共APIQ因此可以被例如javadoc此类的工h档化?br />
Documented是一个marker annotationQ没有成员?br />
4QInherited
@Inherited meta-annotation也是一个marker annotationQ它阐述了某个被标注的类型是被承的。如果一个用了@Inherited修饰的annotationcd被用于一个classQ? 则这个annotation被用于该class的子cR?br />
注意Q@Inherited annotationcd是被标注q的class的子cLl承。类q不从它所实现的接口承annotationQ方法ƈ不从它所重蝲的方法承annotation?br />
? 得思考的是,当@Inherited annotationcd标注的annotation的Retention是RetentionPolicy.RUNTIMEQ则反射API增强了这U 承性。如果我们用java.lang.reflectL询一个@Inherited annotationcd的annotationӞ反射代码查将展开工作Q检查class和其父类Q直到发现指定的annotationcd被发玎ͼ 或者到辄l承l构的顶层?br />
六、ȝQ?/span>

             本文几乎覆盖了所有的Annotation的概念和知识点,从annotation的定义、语法到工作原理、如何自定义 annotationQ直? meta- annotation。其中也h一些配套的代码片断可参考,虽然不是很多Q但是可谓言意赅、着光点,本h认ؓ用好annotation的关键还在于 使用。希望本手册能够帮助大家用好annotationQ这也是本h的最大快乐?

咖啡企鹅 2010-01-19 15:30 发表评论
]]>
վ֩ģ壺 | | Դ| Ϊ| | | | Ҧ| ³| ɽ| 㽭ʡ| ָɽ| | | | | | ʯ| | ͷ| ľ| | ֲ| Ϸ| | ǭ| ɽ| | | ½| | | | | | | ƽ| ͨ| | | ذ|