学习java的人都知道java中有javadoc这样的java注解,这类注解是用来生成帮助文档用的。
在EJB、Spring、Hibernate、Struts现都可用注解方式配置应用,但是我们对java annotation又有多少了解呢
其实annotation说是元数据(元数据大家应该不陌生--元数据 最本质、最抽象的定义为: data about data (关于数据的数据-- 关于数据的数据或者叫做用来描述数据的数据 )
元数据的作用
如果要对于元数据的作用进行分类,目前还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:
l 编写文档:通过代码里标识的元数据生成文档。
l 代码分析:通过代码里标识的元数据对代码进行分析。
l 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
先看看怎么定义一个annotation
public @interface TestMethodAnnotation {
}
就是在定义接口的interface前加@
再看使用方法
@TestMethodAnnotation
public String getName() {
return name;
}
添加变量
public @interface TestMethodAnnotation {
boolean serialize() default true;
}
@TestMethodAnnotation(serialize = false)
public String getName() {
return name;
}
为变量赋默认值
public @interface TestMethodAnnotation {
boolean serialize() default true;
}
限定注释使用范围
当我们的自定义注释不断的增多也比较复杂时,就会导致有些开发人员使用错误,主要表现在不该使用该注释的地方使用。为此,Java 提供了一个ElementType 枚举类型来控制每个注释的使用范围,比如说某些注释只能用于普通方法,而不能用于构造函数等。下面是Java 定义的ElementType 枚举:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE
}
添加使用范围
@Target(ElementType.METHOD)
public @interface TestMethodAnnotation {
boolean serialize() default true;
}
这样表明该annotation只能用于方法注解
注释保持性策略
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
CLASS 编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。即要通过java反射得到它是得不到的 |
RUNTIME 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 |
SOURCE 编译器要丢弃的注释。即要通过java反射得到它是得不到的 |
使用策略;
注释保留策略。此枚举类型的常量描述保留注释的不同策略。它们与 Retention
元注释类型一起使用,以指定保留多长的注释。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMethodAnnotation {
boolean serialize() default true;
}
运行时注解的读取
类类型注解
TestBean testbean = new TestBean();
Class clazz = testbean.getClass();
TestClassAnnotation testClassAnnotation = (TestClassAnnotation) clazz
.getAnnotation(TestClassAnnotation.class);
方法类型注解
Method readMethod = prop.getReadMethod();
System.out.print(",readMethod:" + readMethod.getName());
。。。。。。。。。。。。。。。
TestMethodAnnotation testAnnotation = readMethod
.getAnnotation(TestMethodAnnotation.class);
if (testAnnotation != null) {
System.out.println("serialize:"
+ testAnnotation.serialize());
}
以下为完整的测试用例:
只能用于方法类型
package com.parkingfo.test.annotation;
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)
public @interface TestMethodAnnotation {
boolean serialize() default true;
}
只能用于类类型
package com.parkingfo.test.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestClassAnnotation {
String descript();
}
使用
package com.parkingfo.test;
import com.parkingfo.test.annotation.TestClassAnnotation;
import com.parkingfo.test.annotation.TestMethodAnnotation;
@TestClassAnnotation(descript = "这是测试描述")
public class TestBean extends Object {
private String name;
@TestMethodAnnotation(serialize = false)
public String getName() {
return name;
}
/**
* @param name
*/
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return super.toString();
}
}
测试类
package com.parkingfo.test;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import com.parkingfo.test.annotation.TestClassAnnotation;
import com.parkingfo.test.annotation.TestMethodAnnotation;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
TestBean testbean = new TestBean();
Class clazz = testbean.getClass();
TestClassAnnotation testClassAnnotation = (TestClassAnnotation) clazz
.getAnnotation(TestClassAnnotation.class);
System.out.println(testClassAnnotation.descript());
BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor prop : props) {
String propName = prop.getName();
System.out.print("propterty:" + propName);
Method readMethod = prop.getReadMethod();
System.out.print(",readMethod:" + readMethod.getName());
Method writeMethod = prop.getWriteMethod();
if (writeMethod != null) {
System.out.print(",writeMethod:" + writeMethod.getName());
}
System.out.println();
TestMethodAnnotation testAnnotation = readMethod
.getAnnotation(TestMethodAnnotation.class);
if (testAnnotation != null) {
System.out.println("serialize:"
+ testAnnotation.serialize());
}
}
} catch (IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试类中用到了得到javabean信息的类Introspector的getBeanInfo(Class clazz)方法得到javabean的信息
转自http://blog.csdn.net/buyaore_wo/archive/2010/09/27/5909754.aspx