概述
通过反射可以获取类、方法、字段的注解信息,具体方法如下:
- isAnnotationPresent(Class annotationClass):判断注解是否存在。
- getAnnotation(Class annotationClass):获取对应类型的注解
- getDeclaredAnnotation(Class annotationClass):获取指定注解
- getAnnotations():获取全部注解
- getDeclaredAnnotations():获取全部注解,但忽略继承的注解
- getAnnotationsByType(Class annotationClass):有默认实现,获取指定注解,获取不到从子类递归获取,一般用于@Repeatable修饰的注解
- getDeclaredAnnotationsByType(Class annotationClass):有默认实现,获取指定注解,忽略继承的注解,一般用于@Repeatable修饰的注解
先通过反射获取类对象、Method对象、Field对象,然后通过这些对象调用上述方法,获取相应的注解信息。
示例
类注解MyClass:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyClass {
String name();
}
方法注解MyMethod:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethod {
}
字段注解MyField:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyField {
String value();
}
定义一个测试类AnnotationUtil,用上面的注解表示该类、方法、字段:
@MyClass(name = "class")
class AnnotationUtil{
@MyField(value = "field")
public int num;
@MyMethod
public void test(){
}
}
测试类AnnotationTest:
public class AnnotationTest {
public static void main(String[] argv) throws NoSuchMethodException, NoSuchFieldException {
// isAnnotationPresent
boolean annotation = AnnotationUtil.class.isAnnotationPresent(MyClass.class);
System.out.println(annotation);
// getAnnotation
MyClass annotation1 = AnnotationUtil.class.getAnnotation(MyClass.class);
System.out.println(annotation1.name());
// getAnnotations
Annotation[] annotations = AnnotationUtil.class.getAnnotations();
for (Annotation ann : annotations) {
System.out.println(ann);
}
System.out.println("++++++++++++");
// Method 获取 getAnnotation
Method method = AnnotationUtil.class.getMethod("test");
MyMethod annotation2 = method.getAnnotation(MyMethod.class);
System.out.println(annotation2);
// Method 获取 getAnnotations
Annotation[] annotations1 = method.getAnnotations();
for (Annotation ann : annotations) {
System.out.println(ann);
}
System.out.println("++++++++++++");
// Field 获取 getAnnotation
Field field = AnnotationUtil.class.getField("num");
MyField annotation3 = field.getAnnotation(MyField.class);
System.out.println(annotation3.value());
// Field 获取 getAnnotations
Annotation[] annotations2 = field.getAnnotations();
for (Annotation ann : annotations2) {
System.out.println(ann);
}
}
}
输出:
true
class
@注解.MyClass(name=class)
++++++++++++
@注解.MyMethod()
@注解.MyClass(name=class)
++++++++++++
field
@注解.MyField(value=field)
通过反射获取类对象、Method对象、Field对象,然后通过这些对象获取对应的注解信息。
@Repeatable
表示这个声明的注解是可重复的。@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。
FileType 注解
@Target( METHOD )
@Retention( RetentionPolicy.RUNTIME )
@Repeatable( FileTypes.class )
public @interface FileType {
String value();
};
FileTypes 注解
@Target( METHOD)
@Retention( RetentionPolicy.RUNTIME )
public @interface FileTypes {
FileType[] value();
}
@FileType注解上的元注解@Repeatable中的值使用了@FileTypes注解。
@FileTypes 注解中包含的值类型是一个@FileType注解的数组。
调用:
public class FindFiles {
public static void main(String[] argv) throws NoSuchMethodException {
FileType[] annotations = FindFiles.class.getMethod("test").getAnnotationsByType(FileType.class);
for(FileType fileType : annotations){
System.out.println(fileType.value());
}
}
@FileType("java")
@FileType("txt")
@FileType("jsp")
public static void test(){
}
}
输出:
java
txt
jsp
public T[] getAnnotationsByType(Class annotationClass);可以获取注解集合。
应用
按指定的顺序获取JavaBean中的属性和方法
MyBean.java:
public final class MyBean {
@BeanFieldAnnotation(order = 2)
private String number;
@BeanFieldAnnotation(order = 1)
private String dates;
@BeanMethodAnnotation(order = 1)
public String getNumber() {
return number;
}
//@BeanMethodAnnotation(order = 3)
public void setNumber(String number) {
this.number = number;
}
@BeanMethodAnnotation(order = 2)
public String getDates() {
return dates;
}
//@BeanMethodAnnotation(order = 4)
public void setDates(String dates) {
this.dates = dates;
}
}
BeanFieldAnnotation.java:
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeanFieldAnnotation {
/**
* 标注该属性的顺序
* @return 该属性的顺序
*/
int order();
}
BeanMethodAnnotation.java:
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeanMethodAnnotation {
/**
* 标注该属性的顺序
* @return 该属性的顺序
*/
int order();
}
MyBeanTest.java:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class MyBeanTest {
public static void main(String[] args){
MyBean mb=new MyBean();
Field fields[] = mb.getClass().getDeclaredFields();
List<Field> fl=getOrderedField(fields);
Method methods[] = mb.getClass().getDeclaredMethods();
List<Method> ml=getOrderedMethod(methods);
System.out.println("属性");
for(Field f:fl){
System.out.println(f);
}
System.out.println("方法");
for(Method m:ml){
System.out.println(m);
}
}
private static List<Field> getOrderedField(Field[] fields){
// 用来存放所有的属性域
List<Field> fieldList = new ArrayList<>();
// 过滤带有注解的Field
for(Field f:fields){
if(f.getAnnotation(BeanFieldAnnotation.class)!=null){
fieldList.add(f);
}
}
// 这个比较排序的语法依赖于java 1.8
fieldList.sort(Comparator.comparingInt(
m -> m.getAnnotation(BeanFieldAnnotation.class).order()));
return fieldList;
}
private static List<Method> getOrderedMethod(Method[] methods){
// 用来存放所有的方法域
List<Method> methodList = new ArrayList<>();
// 过滤带有注解的方法
for(Method m:methods){
if(m.getAnnotation(BeanMethodAnnotation.class)!=null){
methodList.add(m);
}
}
// 这个比较排序的语法依赖于java 1.8
methodList.sort(Comparator.comparingInt(
m -> m.getAnnotation(BeanMethodAnnotation.class).order()));
return methodList;
}
}