Java注解

1、 注解的意义
假如你想为应用设置很多的常量或参数,这种情况下,XML是一个很好的选择,因为它不会同特定的代码相连。如果你想把某个方法声明为服务,那么使用Annotation会更好一些,因为这种情况下需要注解和方法紧密耦合起来,开发人员也必须认识到这点。Annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用Annotation,开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。
1)为编译器提供辅助信息:Annotations可以为编译器提供而外信息,以便于检测错误,抑制警告等。
2)编译源代码时进行而外操作:软件工具可以通过处理Annotation信息来生成原代码,xml文件等。
3)运行时处理:有一些annotation甚至可以在程序运行时被检测,使用注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理。
注意:不要滥用注解,平常我们编程过程很少接触和使用注解,只有做设计,且不想让设计有过多的配置时,才会考虑使用。
2、注解的格式:
定义新的Annotation类型使用@interface关键字: public @interface 注解名 {定义体}
Annotation定义体需要注意:
第一、只能用public或默认(default)这两个访问权修饰。例如:String value(),这里把方法设为defaul默认类型。
第二、参数成员只能用八种基本数据类型和String、Enum、Class、Annotations等数据类型,以及这一些类型的数组。例如:String value(),这里的参数成员就为String。
第三、如果只有一个参数成员,最好把参数名称设为“value“,后加小括号。
第四、注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此,使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。
Annotation只有成员变量,没有方法。Annotation的成员变量在Annotation定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

public @interface MyTag{
    string name();
    int age();
}
 
3、元注解
Annotations仅仅是元数据,和业务逻辑无关。
@Documented:一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。如果定义注解A时,使用了@Documented修饰定义,则在用javadoc命令生成API文档后,所有使用注解A修饰的程序元素,将会包含注解A的说明。
@Retention:定义该注解的生命周期。
RetentionPolicy.SOURCE:在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
RetentionPolicy.CLASS:在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
RetentionPolicy.RUNTIME:始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
注意:要想使用反射去读取注解,必须将Retention的值选为Runtime。
@Target:表示该注解用于什么地方。如果不明确指出,该注解可以放在任何地方。以下是一些可用的参数。
ElementType.TYPE:用于描述类、接口或enum声明
ElementType.FIELD:用于描述实例变量
ElementType.METHOD
ElementType.PARAMETER
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.ANNOTATION_TYPE 另一个注释
ElementType.PACKAGE 用于记录java文件的package信息

@Inherited:定义该注释和子类的关系:阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类,注意注解继承只针对class 级别注解有效。
4、小例子
在定义注解时,不能继承其他的注解或接口。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
public enum Priority {LOW, MEDIUM, HIGH}
public enum Status {STARTED, NOT_STARTED}
String author() default "Yash";
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;
}
 
使用该注解:

@Todo(priority = Todo.Priority.MEDIUM, author = "Yashwant", status = Todo.Status.STARTED)
public void incompleteMethod1() {
//Some business logic is written
}
 
如果注解中只有一个属性,可以直接命名为“value”,使用时无需再标明属性名。

@interface Author{
String value();
}
@Author("Yashwant")
public void someMethod() {
}
 
5、提取Annotation信息(反射技术)
如果你熟悉反射代码,就会知道反射可以提供类名、方法和实例变量对象。所有这些对象都有getAnnotation()这个方法用来返回注解信息。我们需要把这个对象转换为我们自定义的注释(使用 instanceOf()检查之后),同时也可以调用自定义注释里面的方法。

Class businessLogicClass = BusinessLogic.class;
for(Method method : businessLogicClass.getMethods()) {
Todo todoAnnotation = (Todo)method.getAnnotation(Todo.class);
if(todoAnnotation != null) {
System.out.println(" Method Name : " + method.getName());
System.out.println(" Author : " + todoAnnotation.author());
System.out.println(" Priority : " + todoAnnotation.priority());
System.out.println(" Status : " + todoAnnotation.status());
}
}

JDK主要提供了两个类,来完成Annotation的提取:
1)java.lang.annotation.Annotation接口:这个接口是所有Annotation类型的父接口(后面会分析Annotation的本质,Annotation本质是接口,而java.lang.annotation.Annotation接口是这些接口的父接口)。 是所有注解继承的接口,并且是自动继承,不需要定义时指定,类似于所有类都自动继承Object。
2)java.lang.reflect.AnnotatedElement接口:该接口代表程序中可以被注解的程序元素。
AnnotatedElement接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:
方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
经典参考:
http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html
http://www.open-open.com/lib/view/open1423558996951.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值