1、什么是注解
用一个词就可以描述注解,那就是元数据,即一种描述数据的数据。所以,可以说注解就是源代码的元数据。
@Override
public String toString() {
return "This is String Representation of current object.";
}
4
1
2
public String toString() {
3
return "This is String Representation of current object.";
4
}
如上代码,重写了toString()方法并使用了@Override注解。但是,即使不使用@Override注解标记代码,程序也能够正常执行。那么,该注解表示什么?有什么好处?
事实上,@Override告诉编译器这个方法是一个重写方法(描述方法的元数据),如果父类中不存在该方法,编译器便会报错,提示该方法没有重写父类中的方法。如果我不小心拼写错误,例如将toString()写成了toStrring(),而且我也没有使用@Override注解,那程序依然能编译运行,但运行结果会和我期望的大不相同。
2、注解的意义
在进行Java程序开发的时候,免不了和各种配置文件打交道,以经典的框架Spring或者Hibernate来说,不论是IOC的bean配置,还是持久化的ORM映射关系配置,都有各自的xml格式的配置文件。
这些配置文件都必须与Java代码同步,否则的话就会出现问题。然而把同一份信息保存在两个地方,并不是一个好的主意,因为维护随着代码量会越来越繁琐,理想的情况下把配置信息和代码都在同一个地方维护就好了。
JDK5中引入了注解机制,它类似于代码中的注释,不同的是注解不是提供代码功能的说明,而是实现程序功能的重要组成部分。在Spring或者Hibernate等主流框架中我们已经可以看到,已经开始可以使用注解的方式来替代xml配置文件,达到简化程序配置的目的。
3、元注解
元注解的作用就是负责注解其他注解。
Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其他annotation类型作说明:
- @Target 注解用于什么地方
- @Retention 注解类型的存活时间
- @Documented 注解是否包含在JavaDoc中
- @Inherited 是否允许子类继承该注解
3.1 @Target
@Target 说明了Annotation所修饰的范围,表示该注解用于什么地方,如果不明确指出,该注解可以放在任何地方:
- packages
- types(类、接口、枚举、Annotation类型)
- 类型成员(方法、构造方法、成员变量、枚举值)
- 方法参数和本地变量(如循环变量、catch参数)
以下是一些可用的参数:
- ElementType.TYPE (描述类、接口、注解、或者枚举)
- ElementType.FIELD (描述实例变量)
- ElementType.METHOD (描述方法)
- ElementType.PARAMETER (描述参数)
- ElementType.CONSTRUCTOR (描述构造方法)
- ElementType.LOCAL_VARIABLE (描述局部变量)
- ElementType.ANNOTATION_TYPE (描述另一个注解)
- ElementType.PACKAGE (描述包)
示例:
(1)注解Table可以用于注解类、接口(包括注解类型) 或enum声明
(2)注解NoDBColumn仅可用于注解类的成员变量
@Target(ElementType.TYPE)
public @interface Table {
/**
* 数据表名称注解,默认值为类名称
* @return
*/
public String tableName() default "className";
}
@Target(ElementType.FIELD)
public @interface NoDBColumn {
}
x
1
ElementType.TYPE) (
2
public @interface Table {
3
/**
4
* 数据表名称注解,默认值为类名称
5
* @return
6
*/
7
public String tableName() default "className";
8
}
9
10
ElementType.FIELD) (
11
public @interface NoDBColumn {
12
13
}
3.2 @Retention
某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。
使用这个meta-Annotation可以对Annotation的“生命周期”限制,即@Retention定义了该Annotation被保留的时间长短。
以下是一些可用的参数:
- RetentionPoicy.SOURCE (源文件中有效,即源文件保留)
- RetentionPoicy.CLASS (class文件中有效,即class保留)
- RetentionPoicy.RUNTIME (运行时有效,即运行时保留)
示例:
(1)Column注解的的RetentionPolicy的属性值是RUNTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理
(2)@Column是个修饰属性的,在运行时有效的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}
1
ElementType.FIELD) (
2
RetentionPolicy.RUNTIME) (
3
public @interface Column {
4
public String name() default "fieldName";
5
public String setFuncName() default "setField";
6
public String getFuncName() default "getField";
7
public boolean defaultDBValue() default false;
8
}
3.3 @Documented
该注解用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
3.4 @Inherited
该注解是一个标记注解,阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。