星期二, 十二月 01, 2015 18:30:08 ??
?
给编译器看的注释---Annotation
?
? ? ? ?Annotation功能建立在反射机制之上,通过Annotation可以对程序进行注释操作。
系统内建Annotation、如何自定义Annotation、反射和Annotation的关联,
以及如何通过Annotation生产Docunmented。
?
本章要点
? ?掌握Annotation的相关概念
? ?熟悉自定义Annotation的方法
? ?了解反射和Annotation的关联
?
一、Annotation
?
? ? Annotation ?实际上表示的是一种注释的语法。
在java中最早的程序是提倡程序与配置代码相分离,
而最新的理论是将所有的配置直接写到程序之中,如果想完成这样的功能,就要使用Annotation。
?
?
二、系统内建的Annotation
?
? ? 在jdk1.5之后的系统中,内建了3个Annotation:
? ? ? ? @Override、@Deprecated、@SuppressWarinings。
?
2.1 @Override
? ? 表示进行正确的覆写操作
?
? ?即使覆盖的方法名称写错了,也不会有任何的提示。
此时,为了保证程序可以正确地进行覆盖操作,在覆盖的时候可以明确地使用@Override表示方法是属于覆盖的操作。
??
?代码案例:
package day30; public class OverrideTest { public static void main(String[] args) { Student s = new Student(); System.out.print("..."+s.say()); } } class Person { public String say() { return "Person_say()"; } } //要求增加此类的子类,覆盖其方法 class Student extends Person { /*为了保证程序可以正确地进行覆盖操作, * 在覆盖的时候可以明确地使用@Override表示方法是属于覆盖的操作。*/ @Override public String say() { return "Student_say()"; } }
?
运行结果:
...Student_say()
?
2.3@Deprecated
? @Deprecated注释表示不建议使用的操作。
例如之前在讲解线程的时候,曾经讲解过线程中的stop()、resume()、suspend()等方法是不建议使用的。
??
代码案例:
package day30; public class DeprecatedTest { public static void main(String[] args) { System.out.print((new Info()).getInfo()); } } class Info { /*@Deprecated注释表示不建议使用的操作。*/ @Deprecated public String getInfo() { return "getInfo()...."; } }
?
运行结果:
getInfo()....
?
2.4 @SuppressWarnings
?
?@SuppressWarnings表示的是压制警告。
如果有一些警告信息则可压制掉,不出现警告的提示。
?
@SuppressWarnings(“deprecation”)
?
使用SuppressWarnings操作的时候可以同时压制多个警告
通过SuppressWarnings的类,可以发现在此类中存在一个value的字符串数组。
?
?
?
Person类中既继承了Info类,又实现了序列化的接口,所有此时会出现多个警告。
或者可以明确的表示,是为SuppressWarnings中的value属性赋值。
?
代码案例:
?
package day30; import java.io.Serializable; public class SuppressWarningsTest { @SuppressWarnings("deprecation") public static void main(String[] args) { System.out.print((new Infos()).getInfos()); } } class Infos { @Deprecated public String getInfos() { return "....getInfos"; } } @SuppressWarnings(value = {"serial","deprecation"}) class Persona extends Infos implements Serializable { /*Person类中既继承了Info类,又实现了序列化的接口,所此时会出现多个警告。*/ }
?
?
运行结果:
....getInfos
?
三、自定义Annotation
?
?
? ? 3.1定义Annotation的语法
? ? ? public @interface Annotation的名称{}
?
? ?案例:
? ? public @interface MyAnnotation{
? ? }
?
如果现在使用此Annotation的话,若不在同一个包中,则需要导入,导入之后使用@的形式反问,语法@MyAnnotation
? ? @MyAnnotation
? ? public class Info{
? ? }
? ? ??
在一个Annotation中实际上也可以定义若干个属性。
? ? ? ?public @interface MyAnnotation{
? ? ? ? ? ? ? ? ?public String key();
? ? ? ? ? ? ? ? ?public String value();
? ? ? ?}
?
? ?在此时Annotation中定义了key和value两个变量,若此时要使用Annotation的话,则必须明确地给出具体的内容。
?
? ? @MyAnnotation(key="MLDN",value="www.baidu.com")
?
?
?
如果现在希望为一个Annotation设置默认内容的话,可以通过default完成。
? ? ? ?public @interface MyAnnotation{
? ? ? ? ? ? ? ? ?public String key() ?default “LXX”;
? ? ? ? ? ? ? ? ?public String value() default “HA”;
? ? ? ?}
?
如果没有设置内容,则将默认值去除继续使用。
?
Annotation中的变量内容可以通过枚举指定范围。
?public enum Color {
? ? ?RED,GREEN,BLUE;
}
?
案例:
? ? ? ?
? ? ? public @interface MyAnnotation{
? ? ? ? ? ? ? ? ?public String key() ?default “LXX”;
? ? ? ? ? ? ? ? ?public String value() default “HA”;
? ? ? ? ? ? ? ? ?public Color color() default Color.RED;
? ? ? ?}
?
如果现在在Info类中使用Annotation的时候并没有指定其规定范围的内容,则会出现错误。
?
? ?@MyAnnotation(color = “red”)
? ? ? public class Info {
? ? }
?
Annotation中的变量还可以使用一个数组表示。
? public @interface MyAnnotation{
? ? ? ? ? ? ? ? ?public String key() ?default “LXX”;
? ? ? ? ? ? ? ? ?public String value() default “HA”;
? ? ? ? ? ? ? ? ?public Color color() default Color.RED;
? ? public String[] url();
? ? ? ?}
?
以后在使用的时候必须按照数组的方式操作。
? ? @MyAnnotation(url = {“www.baidu.com”,“www.baidu.com”})
? ? ? public class Info {
? ? }
?
四、Retention和RetentionPolicy
?
? ?
软件包 java.lang.annotation?
Retention 指示注释类型的注释要保留多久。
?
Retention本身是一个Annotation,其中的取值是通过RetentionPolicy这个枚举类型指定的范围。
?
在RetentionPolicy中规定了以下3个作用范围。
? ? ? ?1.只在源代码中起作用:public static final RetentionPolicy SOURCE
? ? ? ?2.只在编译之后的class中起作用: public static final RetentionPolicy CLASS
? ? ? ?3.在运行的时候起作用:public static final RetentionPolicy RUNTIME
如果一个Annotation要想起作用,则必须使用RUNTIME范围。
任何一个自定义Annotation都是继承了java.lang.annotation.Annotaion接口。
?
五、反射与Annotation
?
?
一个Annotation如果想起作用,则肯定要依靠反射机制。通过反射可以取得在一个方法上声明的Annotation的全部内容。
?
Field、Method、Constructor的父类上定义了以下与Annotation反射操作相关的方法。
?
1.取得全部的Annotation: public Annotation[] getAnnotations()
2.判断操作的是否是指定的Annotation。
? public boolean isAnnotationPresent(Class<? entends Annotation> annotationClass)
?
?
?
5.1 取得全部的Annotation
?
? ?代码案例:
package day30; public class Info { @Override @Deprecated @SuppressWarnings(value="_") //现在在一个方法上使用3个内建的Annotation public String toString(){ return "Hello"; } } package day30; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class ClassAnnotationTest { public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException { Class<?> cls = Class.forName("day30.Info"); Method mtd = cls.getMethod("toString"); Annotation ant[] = mtd.getAnnotations(); //取得全部的Annotation for(int i = 0;i<ant.length;i++) { System.out.print(""+ant[i]); } } }
?运行结果:
@java.lang.Deprecated()
?
这3个内建的Annotation中只有@Deprecated是RUNTIME类型。
实践证明,如果在程序运行的时候当取得了全部的Annotation时,只能取得一个。
?
?
此案例很好的证明了只有在Runtime范围中国的自定义的才可以被用户找到。
?
?
5.2 加入自定义的Annotation
?
? ?在一个自定义的Annotation编写的时候,如果要想让其有意义,则必须使用RUNTIME声明范围。
@Retention(value = RetentionPolicy.RUNTIME)
?
代码案例:
package day30; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; //在一个自定义的Annotation编写的时候,如果要想让其意义,则必须使用RUNTIME声明范围。 @Retention(value=RetentionPolicy.RUNTIME) public @interface MyAnnotation { public String key() default "zhuhw"; public String value(); } 此后在Info类中增加此Annotation package day30; public class Info { //此后在Info类中增加此Annotation @Override @Deprecated @SuppressWarnings(value="_") @MyAnnotation(key = "waxun",value = "www.baidu.com") //现在在一个方法上使用3个内建的Annotation public String toString(){ return "Hello"; } } 在使用的时候真正需要取得的是向自定义Annotation中设置的内容 package day30; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class AnnotationTest { public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException{ Class<?> clsa = Class.forName("day30.Info"); Method m2 = clsa.getMethod("toString"); Annotation att[] = m2.getAnnotations(); //取得全部的Annotation for(int i =0;i<att.length;i++) { if(m2.isAnnotationPresent(MyAnnotation.class)) { //声明Annotation对象 MyAnnotation ma = null; ma = m2.getAnnotation(MyAnnotation.class); String key = ma.key(); String value = ma.value(); System.out.println(key+"-->"+value); } } } }
?运行结果:
waxun-->www.baidu.com
waxun-->www.baidu.com
?
?
?
在实际开发中,不用关心这些低层的操作原理,在程序使用中都会为其提供支持。
?
?
六、深入Annotation
?
? 在java.lang.annotation中存在以下的Annotation:
? ? ? Target、Documended、Inherited
?
一个自定义的Annotation可以在任意的位置使用
?
例如:
?
? ?@MyAnnotation
? ?public class Info{
@MyAnnotation
? ? ? ?private ?String name;
? ? ? ?@MyAnnotation
? ? ? ?public String toString() {
? ? ? ? ?return "HELLO";
? ? ? ? }
? ?}
?
因为可以在任意的位置上使用,因此在操作的时候就会出现一些问题,例如一些Annotation只希望在方法的声明上使用。
那么此时,就必须设置Annotation的作用范围。
?
?
在@Target注释中,存在EleentType类型的变量,在此变量中存在7种范围。
? ? 1.只能在Annotation中出现: public static final ElementType ANNOTATION_TYPE
? ? 2.只能在构造方法中出现: public static final ElementType CONSTRUCTOR
? ? 3.本地变量上使用:public static final ElementType LOCAL_VARIABLE
? ? 4.只能在方法上使用: public static final ElementType METHOD
? ? 5.在参数声明上使用: public static final ElementType PARAMETER
? ? 6.在包声明上使用: public static final ElementType PACKAGE
? ? 7.只能在类或接口上使用: public static final ElementType TYPE
?
例子:
package day30; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Target(value = ElementType.METHOD) @Retention(value=RetentionPolicy.RUNTIME) public @interface MyAnnotation { public String key() default "zhuhw"; public String value() default "waxun"; } 此Annotation只能在方法上使用。 或者可以同时制定多个范围。 例子: package day30; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value = {ElementType.METHOD,ElementType.TYPE}) //在一个自定义的Annotation编写的时候,如果要想让其意义,则必须使用RUNTIME声明范围。 @Retention(value=RetentionPolicy.RUNTIME) public @interface MyAnnotation { public String key() default "zhuhw"; public String value(); }
?6.2 Docunmented注释
? ?此种表示的是文档的注释格式
?
代码案例:
package day30; 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 @Target(value = {ElementType.METHOD,ElementType.TYPE}) @Retention(value=RetentionPolicy.RUNTIME) public @interface MyAnnotation { public String key() default "zhuhw"; public String value(); } 在使用类中可以加入文档注释。 package day30; @MyAnnotation public class Info { private String name; /* * 本方法是覆盖Obiect类中的toString()方法 */ @MyAnnotation public String toString(){ return "Hello"; } }
?加入文档注释后,程序的最大好处是可以在doc文档中出现。
在mye中直接支持javadoc文档的生成。
导出项目有一个javadoc文档的生成
?
?
?
6.3 Inherited
? 表示一个Annotation能否被使用其类的子类继承下去。
如果没有写上此注释,则此Annotation根本就是无法继承。
?
案例:
package day30; 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; @Inherited @Documented @Target(value = {ElementType.METHOD,ElementType.TYPE}) @Retention(value=RetentionPolicy.RUNTIME) public @interface MyAnnotation { public String key() default "zhuhw"; public String value()default "waxun"; }
?此Annotation可以被子类继承。
?
星期二, 十二月 01, 2015 23:50:03
原文:http://yuzhouxiner.iteye.com/blog/2260935