参考该文章:http://www.cnblogs.com/mouseIT/p/5033746.html
作者补充了注解解析
注解格式
@Documented
@Inherited
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
//定义注解类
public @interface Book{
//定义Book的书名
String bookname();
//定义Book的价格,默认99.9
Double price() default 99.9;
//定义作者数组,其中
String[] authors();
}
详解
元注解
- @Target 注释的使用位置.
- @Retention 注解的声明周期.
- @Documented
- @Inherited 被该注解标记类的,子类都继承该注解
@Target
- 作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用。
- 可选的参数值在枚举类ElemenetType中包括:
TYPE: 用在类,接口上
FIELD:用在成员变量上
METHOD: 用在方法上
PARAMETER:用在参数上
CONSTRUCTOR:用在构造方法上
LOCAL_VARIABLE:用在局部变量上
@Retention
- 作用:定义该注解的生命周期(有效范围)。
- 可选的参数值在枚举类型RetentionPolicy中包括
SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。
CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。
RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。【常用】
@Inherited:
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
@Documented:
该属性用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
注解类的成员属性
注解参数的可支持数据类型:
- 1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
- 2.String类型
- 3.Class类型
- 4.enum类型
- 5.Annotation类型
- 6.以上所有类型的数组
Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
对注解的解析
- 在对注解类进行确定之后,便是解析注解
原理
通过反射,拿到注解类的class字节码文件,再获取到注解类的属性
-
什么是注解解析
-
通过Java技术获取注解数据的过程则称为注解解析。
与注解解析相关的接口
Anontation:所有注解类型的公共接口,类似所有类的父类是Object。
AnnotatedElement:定义了与注解解析相关的方法,常用方法:
boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有指定的注解,有则返回true,否则返回false。
T getAnnotation(Class annotationClass); 获得当前对象上指定的注解对象。
3.5.3 获取注解数据的原理
-
注解作用在那个成员上,就通过反射获得该成员的对象(Filed)来得到它的注解。
-
如注解作用在方法上,就通过方法(Method)对象得到它的注解*
-
如注解作用在类上,就通过Class对象得到它的注解
//对类进行注解 ElementType.TYPE
@Book(value = "西游记1", price=9988, authors = {"吴承恩1", "白求恩1"})
public class BookShelf {
private int id;
//对方法进行注解 ElementType.METHOD
@Book(value = "西游记", price = 998, authors = {"吴承恩", "白求恩"})
public void show() {
//定义变量
String value = "";
int price = 0;
String[] authors = {};
//获取当前类的Class对象
Class<? extends BookShelf> cls = this.getClass();
try {
//获取当前方法对象
Method show = cls.getMethod("show");
//判断当前方法上是否有注解
if (show.isAnnotationPresent(Book.class)) {
Book book = show.getAnnotation(Book.class);
value = book.value();
price = book.price();
authors = book.authors();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("书名为 : " + value);
System.out.println("价格为 : " + price);
System.out.println("作者为 : " + Arrays.toString(authors));
}
}
Test1
class Test1 {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf();
bookShelf.show();
}
}
Test2
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("DataSource.BookShelf");
if(cls.isAnnotationPresent(Book.class)){
Book book = cls.getAnnotation(Book.class);
String value = book.value();
int price = book.price();
String[] authors = book.authors();
System.out.println("value = " + value);
System.out.println("price = " + price);
System.out.println("authors = " + Arrays.toString(authors));
}
}
}