- Date:2015-5-7
- Tag:java;注解
- Author:踏雪
- Email:shuwoom.wgc@gmail.com
一、 What(是什么?)
注解:是元数据,可以声明在包、类、属性、方法、局部变量、方法参数等前面,用来对这些元素进行说明、注释。
例如下面的toString函数上的@Override就是一个经常用到的注解
元注解:用来注解其他的注解
@Retention
@Target
@Documented
@Inherited
二、 How(如何自定义注解?)
(1)@Retention
描述注解的保留到一个阶段(有效范围)
ReteionPolicy | . |
---|---|
SOURCE | 保留到源代码 |
CLASS | 保留到Class字节码 |
RUNTIME | 保留到运行时 |
代码演示:
注解类:
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface OtherAnnotation {
}
测试:
public static void main(String[] args) {
@OtherAnnotation(name="wgc")
public void test(){
}
AnnotationTest annotationTest = new AnnotationTest();
if(annotationTest.getClass().isAnnotationPresent(MyAnnotation.class)){
System.out.println("Yes1");
} else {
System.out.println("No1");
}
Method method = annotationTest.getClass().getMethod("test", null);
if(method.isAnnotationPresent(OtherAnnotation.class)){
System.out.println("yes2");
} else {
System.out.println("no2");
}
if(method.getClass().isAnnotationPresent(OtherAnnotation.class)){
System.out.println("yes3");
} else {
System.out.println("no3");
}
}
运行结果:
如果将@Retention(RetentionPolicy.SOURCE)改为:
@Retention(RetentionPolicy.CLASS)也是No。
只有改成@Retention(RetentionPolicy.RUNTIME),才返回Yes。
因为isAnnotationPresent方法是在运行阶段判断的,只有注解保留到RUNTIME阶段才能发现。
(2)@Target
说明在哪里使用该注解
ElementType |
---|
ANNOTATION_TYPE |
CONSTRUCTOR |
FIELD |
LOCAL_VARIABLE |
METHOD |
PACKAGE |
PARAMETER |
TYPE |
代码演示:
注解类:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}
测试类:
@MyAnnotation
public class AnnotationTest {
…………….
}
这时候,编译器就会提醒错误,注释的地方不正确。
要想在类外使用注释,应该改成:
@Target({ElementType.METHOD,ElementType.TYPE})
(3)注解的属性
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
//primitive type, String, Class, annotation, enumeration
int id();
String name() default "null";
int[]array();
Color color();
Class clazz();
OtherAnnotation otherAnnotation();
}
@MyAnnotation(id=12,name="wgc",array={1,2,3},color=Color.RED, clazz=String.class,otherAnnotation=@OtherAnnotation(name="other"))
public class AnnotationTest {
public static void main(String[] args) {
AnnotationTest annotationTest = new AnnotationTest();
if(annotationTest.getClass().isAnnotationPresent(MyAnnotation.class)){
System.out.println("Yes");
MyAnnotation myAnnotation = annotationTest.getClass().getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.id());
System.out.println(myAnnotation.array().length);
System.out.println(myAnnotation.color());
System.out.println(myAnnotation.clazz());
System.out.println(myAnnotation.otherAnnotation());
} else {
System.out.println("No");
}
}
}
结果:
- 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
- 跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。也是
- 在编译时进行格式检查。如@Override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
四、反射和注解的综合实例
注解的应用结构图:
综合实例代码:
第一步:实现注解类:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ValueBind {
public enum FieldType{
STRING,INT
};
FieldType type();
String value();
}
第二步:编写使用注解的类
public class Student {
private String name;
private int age;
private String studentID;
public String getName() {
return name;
}
@ValueBind(type=FieldType.STRING, value="wgc")
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
@ValueBind(type=FieldType.INT, value="22")
public void setAge(int age) {
this.age = age;
}
public String getStudentID() {
return studentID;
}
@ValueBind(type=FieldType.STRING, value="12")
public void setStudentID(String studentID) {
this.studentID = studentID;
}
@Override
public String toString() {
return "(" + getName() + "," + getAge() + "," + getStudentID() + ")";
}
}
第三步:对注解的类进行反射
public class PersistStudent {
public static void main(String[] args) throws Exception {
Object obj = Class.forName("com.shuwoom.annotation.sample.Student").newInstance();
Method[]methods = obj.getClass().getDeclaredMethods();
for(Method method : methods) {
if(method.isAnnotationPresent(ValueBind.class)){
ValueBind valueBind = method.getAnnotation(ValueBind.class);
ValueBind.FieldType type = valueBind.type();
String value = valueBind.value();
if(valueBind.type() == ValueBind.FieldType.INT){
method.invoke(obj, Integer.parseInt(value));
} else if(valueBind.type() == ValueBind.FieldType.STRING){
method.invoke(obj, value);
}
}
}
System.out.println((Student)obj);
}
}
输出结果: