Annotation简介
Annotation是JDK1.5引入的特性,包含在java.lang.annotation包中。
它是附加在代码中的一些元信息,将一个类的外部信息与内部成员联系起来,在 编译、运行时进行解析和使用(可以理解成Python的装饰器)。
Java内置了一些Annotation(例如 @Override、@Deprecated等),也支持用户定义自己的Annotation,像Hibernate、Spring等框架都大量的自定义了Annotation。
什么是Annotation?
用一个词就可以描述Annotation —— "元数据",一种描述“数据”的“数据”;可以说Annotation就是源代码的“元数据”。
@Override
public String toString() {
return "Annotation Demo";
}
上面的代码中重写了 toString()方法,并使用了@Override Annotation。该Annotation表示什么?有什么用处?实际上@Override会告诉编译器这个方法是一个重写方法,如果父类中不存在该方法,编译器就会报错。
Annotation是一种应用与 类、接口、方法、参数、变量、构造器及包声明中的特殊修饰符,详细内容可以查看枚举ElementType。
为什么要引入Annotation?
在Annotation出现之前,XML被广泛应用关于描述元数据,但是程序员和架构师发现XML的维护越来越麻烦,他们希望使用一些和代码紧耦合的东西,而不是想XML那样和代码是松耦合的,最有趣的是XML配置实际上是为了分离代码和配置而引入的。
假如你想为应用设置很多常量或参数,XML是一个很好的选择,因为它不会和特定的代码相连。如果你想把某个Method声明为服务,那么使用Annotation会更简单、方便一些,因为这种情况下需要Annotation和Method紧密耦合起来。
目前需要框架将XML和Annotation两种方式都结合使用,平衡两者之间的利弊。
Annotation是如何工作的?
先来看看@Override的代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
对于@Override你肯定会有疑问,它的内部什么都没做,它是如何检查父类中有没有同名的方法呢?@Override的定义不仅仅只有这么一点代码(注意:Annotation仅仅是元数据,和业务逻辑无关),那@Override到底是如何实现的呢? 答:AnnotationProcessor
Annotation示例代码:https://docs.google.com/file/d/0B1N2DVZFnNU0dVdFVjVFeTVtcXc/edit
AnnotationProcessor
是一个在javac中的,用来编译时扫描和处理的Annotation的工具。一个Annotation的AnnotationProcessor,以Java代码(或者编译过的字节码)作为输入,生成文件(通常是.java文件)作为输出。这具体的含义什么呢?你可以生成Java代码!
生成的Java代码是在新的.java文件中,所以你并不能修改已存在的Java类,例如向已有的类中添加方法。并且这些生成的Java文件,会同其他普通的手动编写的Java源代码一样被javac编译。
元注解
用来标注其它注解而创建的新注解,元注解的类型有以下几种:
@Target:注解所修饰的对象范围
@Inherited:表示注解可以被继承
@Documented:表示这个注解应该被JavaDoc工具记录
@Rentation:用来声明注解的保留策略
@Repeable:JDK8新增,允许一个注解在同一声明类型(类,属性或方法)上多次使用。
自定义Annotation
那么,注解的内部到底是如何定义的呢?Annotations只支持基本类型、String及枚举类型。注释中所有的属性被定义成方法,并允许提供默认值。
示例代码:
01、MyTag类
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.FIELD})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
String name() default "Car";
int size() default 10;
}
02、Car实体类
public class Car {
private String name;
private int size;
public Car(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Car(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", size=" + size +
'}';
}
}
03、AnnotationDemo
public class AnnotationDemo {
@MyTag(name = "Audi", size = 100) // 装配Car这个类
private Car car;
public Car getCar(){
return car;
}
public void setCar(Car car){
this.car = car;
}
@Override
public String toString() {
return "AnnotationDemo{" +
"car=" + car +
'}';
}
}
04、AnnotationProcessor
import java.lang.reflect.Field;
public class AnnotationProcessor {
public static void annotationProcess(AnnotationDemo annotationDemo){
for(Field field: annotationDemo.getClass().getDeclaredFields()){
if(field.isAnnotationPresent(MyTag.class)){ // 如果存在MyTag标签
MyTag myTag = field.getAnnotation(MyTag.class);
annotationDemo.setCar(new Car(myTag.name(), myTag.size()));
}
}
}
public static void main(String[] args){
AnnotationDemo annotationDemo = new AnnotationDemo();
annotationProcess(annotationDemo);
System.out.println(annotationDemo.getCar());
}
}