一、概念:
Annotation它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(
metadata)与程序元素(类、方法、成员变量等)进行关联。更通俗的意思是为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且是供指定的工具或框架使用的。A
nnontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
二、原理:
Annotation其实是一种接口。通过
Java的反射机制相关的
API来访问
annotation信息。 相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。
annotation是不会影响程序代码的执行,无论
annotation怎么变化,代码都始终如一地执行。
annotation是不会影响程序代码的执行,无论
annotation怎么变化,代码都始终如一地执行。
Annotation与interface的异同:
1)、
Annotation类型使用关键字
@interface而不是
interface。
2)、
Annotation类型、方法定义是独特的、受限制的。
Annotation 类型的方法必须声明为
无参数、无异常抛出的。这些方法定义了
annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。而方法返回值类型必须为
primitive类型、
Class类型、枚举类型、
annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用
default和一个默认数值来声明成员的默认值,
null不能作为成员默认值,这与我们在非
annotation类型中定义方法有很大不同。
Annotation类型和它的方法不能使用
annotation类型的参数、成员不能是
generic。只有返回值类型是
Class的方法可以在
annotation类型中使用
generic,因为此方法能够用类转换将各种类型转换为
Class。
3)、
Annotation类型又与接口有着近似之处。
它们可以定义常量、静态成员类型(比如枚举类型定义)。
Annotation类型也可以如接口一般被实现或者继承。
三、应用场合
annotation一般作为一种辅助途径,应用在软件框架或工具中,在这些工具类中根据不同的
annontation注解信息采取不同的处理过程或改变相应程序元素(类、方法及成员变量等)的行为。
例如:
Junit、
Struts、
Spring等流行工具框架中均广泛使用了
annontion。使代码的灵活性大提高。
四、基本语法:
Java目前包括三种标准注解和四种元注解。元注解主要负责注解其他注解的。
三种标准注解:
@Override,表示当前的方法定义覆盖了父类中的方法。必须要有相同的方法签名即(方法名,参数类型,参数顺序,参数个数)都一样。否则在编译过程中发出错误提示。
@Deprecated,对不应该再使用的方法添加注解,当使用这个方法的时候,会在编译时候显示提示信息。
@SuppressWarnings,关闭不当的编译器报警信息
四种元注解:
@Target,表示该注解可以用什么地方。
TYPE : 类、接口或enum声明
FIELD: 域(属性)声明
METHOD: 方法声明
PARAMETER: 参数声明
CONSTRUCTOR: 构造方法声明
LOCAL_VARIABLE:局部变量声明
ANNOTATION_TYPE:注释类型声明
PACKAGE: 包声明
@Retention,表示需要在什么级别保存该注解信息。
1. SOURCE//按照规定使用注释,但是并不将它保留到编译后的类文件中
2. CLASS//将注释保留在编译后的类文件中,但是在运行时忽略它
3. RUNTIME//将注释保留在编译后的类文件中,并在第一次加载类时读取它
@Documented,将此注解包含到Javadoc中。
@Inherited,允许子类继承父类的注解。
五、自定义Annocation
先看一个简单的annocation
package
com.cts.elt.annotation;
import
java.lang.annotation.Documented;
import
java.lang.annotation.Retention;
import
java.lang.annotation.ElementType;
import
java.lang.annotation.RetentionPolicy;
import
java.lang.annotation.Target;
@Target
(ElementType.
TYPE
)
//此注解用在类上面
@Retention
(RetentionPolicy.
RUNTIME
)
//将注释保留在编译后的类文件中,并在第一次加载类时读取它
@Documented
public
@interface
MyAnnotation1
{
String value();
}
|
上面这个MyAnnotation1.class文件包含一个值,下面来一个含有两个值的annotation:
package
com.cts.elt.annotation;
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;
@Target
(ElementType.
METHOD
)
@Retention
(RetentionPolicy.
RUNTIME
)
@Documented
public
@interface
MyAnnotation2
{
String description();
boolean
isAnnotation();
}
|
关键是来看这两个自定义annotation的用法:
package
com.cts.elt.annotation;
@MyAnnotation1
(
"this isannotation1"
)
public
class
AnnotationDemo {
@MyAnnotation2
(description =
"this is annotation2"
, isAnnotation =
true
)
public
void
sayHello() {
System.
out
.println(
"hello world!"
);
}
}
|
如果把@MyAnnotation1与@MyAnnotation2的位置换一换,会怎么样?(肯定报错啦!)
六、自定义Annocation高级篇
情景设计:设有一CLASS叫Student,其中有三个fields:
private String name = ""; private int age = 0; private String studentId = ""; |
相应的每一个field有一对的set, get方法。 然后我在每个set方法上造一个annotation叫ValueBind的注解,其作用是: 只要set方法上带有ValueBind注解,它就会根据这个字段的类型把一个默认值,自动赋给Student类中相对应的field。
1、先来看一下Student类:
package
com.cts.elt.annotation;
import
java.io.Serializable;
import
com.cts.elt.annotation.ValueBind.fieldType;
public
class
Student
implements
Serializable {
private
String name =
""
;
public
String getName() {
return
name;
}
@
ValueBind(type = fieldType.STRING, value = "aa")
public
void
setName(String name) {
this
.name = name;
}
public
int
getAge() {
return
age;
}
@
ValueBind(type = fieldType.INT, value = "30")
public
void
setAge(
int
age) {
this
.age = age;
}
public
String getStudentId() {
return
studentId;
}
@
ValueBind(type = fieldType.STRING, value = "101")
public
void
setStudentId(String studentId) {
this
.studentId = studentId;
}
private
int
age = 0;
private
String studentId =
""
;
}
|
2、自定义一个ValueBind的Annocation:
package
com.cts.elt.annotation;
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;
@Target
(ElementType.
METHOD
)
@Retention
(RetentionPolicy.
RUNTIME
)
@Documented
public
@interface
ValueBind
{
enum
fieldType {
STRING
,
INT
};
fieldType type();
String value();
}
|
首先这个annotation只能被标注在方法上;其次它含有两个值,一个是enum类型,一个是String类型
3、利用Java类反射机制来实现我们的Annocation:
package
com.cts.elt.annotation;
import
java.lang.reflect.*;
public
class
PersistStudent {
public
static
void
main(String[] args)
throws
Exception {
Object c = Class.forName(
"com.cts.elt.annotation.Student"
).newInstance();
try
{
Method[] methodArray = c.getClass().getDeclaredMethods();
for
(
int
i = 0; i < methodArray.
length
; i++) {
if
(methodArray[i].isAnnotationPresent(
ValueBind
.
class
)) {
//如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
ValueBind
annotation = methodArray[i].getAnnotation(
ValueBind
.
class
);
//如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
String type = String.valueOf(annotation.type());
String value = annotation.value();
if
(type.equals(
"INT"
)) {
methodArray[i].invoke(c,
new
Integer[] {
new
Integer(value) });
}
else
{
methodArray[i].invoke(c,
new
String[] { value });
}
}
}
Student annotaedStudent = (Student) c;
System.
out
.println(
"studentId===="
+ annotaedStudent.getStudentId()
+
" studentnName===="
+ annotaedStudent.getName()
+
" student Age===="
+ annotaedStudent.getAge());
}
catch
(Exception e) {
throw
new
Exception(e);
}
}
}
|
运行结果显示:
studentId====101 studentnName====aa studentAge====30 |